二分探索で ソート済み配列から値を探す
小さい
海外で定番の問題リスト 4 本のうち 2 本に入っています (NeetCode 150、Grind 75)
問題
小さいnums と、target をnums のtarget が
numsの値は 小さい 順に 並び、 同じ値は 2 回出てきません numsの長さは 0 以上 10000 以下、 値は どれも -10000 以上 10000 以下です - 時間は O(log n) で
解いてください
入力と出力の例
例 1
例 2
並びに
例 3
端の
面接での聞かれ方
面接では、
- 「ソート済みの
配列から、 目標の 数の インデックスを 返してください。 無ければ -1 です」 - 書き終えた
あとに 「なぜ O(log n) に なるのですか?」と 続けて 聞かれます - 「同じ
値が 何個も あったら、 どの 位置を 返しますか?」と、 問題文に 無い 場合を 聞かれる こともあります
二分探索は
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
アルゴリズムのチートシートの「ソートと二分探索」に、
関わる学び
二分探索は、
まず 考える手順
段 1
まずはtarget と
段 2
並びがtarget より
段 3
探す範囲を left と right の 2 つのleft をright をleft <= right の
解答
Python
Python
def binary_search(nums, target):
left = 0
right = len(nums) - 1
while left <= right:
both = left + right
mid = both // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1JavaScript
JavaScript
function binarySearch(
nums, target
) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = Math.floor(
(left + right) / 2
);
if (nums[mid] === target) {
return mid;
}
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}Go
Go
func binarySearch(
nums []int, target int,
) int {
left := 0
right := len(nums) - 1
for left <= right {
mid := (left + right) / 2
if nums[mid] == target {
return mid
}
if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return -1
}nums がright が -1 からMath.floor で/ のままで
計算量
- 時間は O(log n) です。
1 回見る たびに 範囲が およそ 半分に なるので、 10000 個でも 14 回ほどで 終わります - 使う
記憶は O(1) です。 持つのは left、right、midの 3 つの数だけです - 段 1 の
前から 見る 書き方は、 時間が O(n) です。 並びが 小さい 順という 手が かりを 使うと、 ここまで縮みます
よく ある間違い
- 止まる
条件を left < rightにする。 範囲に数が 1 つだけ 残った ときに 見ずに 抜けてしまい、 例 3 の 10 のような 端の 数を 見落とします left = midやright = midにする。 真ん中はもう 見終わっているので、 1 つずらさないと 範囲が 縮まない 場合が あり、 繰り返しが 止まらなくなります - 真ん中の
求め方で 桁が あふれる。 Python と JavaScript では 起きにくいですが、 整数の 大きさに 上限が ある 言語では、 leftとrightを足した 時点であふれる ことがあります。 その 言語では 「 leftに、2 つの 差の 半分を 足す」 書き方にします
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.2確認日 2026年10月24日
面接での 話し方の例
書き始める
「並びが
小さい 順なので、 真ん中の 数と 比べれば 半分を 捨てられます。 範囲は 両端を 含む形で 持ち、 範囲に 数が 残っている 間だけ 繰り返します。 時間は O(log n)、 記憶は O(1) です。」
書き終えたら、
「例 2 の
[2, 5, 9, 13]で 6 を探します。 最初の 真ん中は 5 で、 6 より 小さいので 左の 端を 9 の 位置へ 動かします。 次の 真ん中は 9 で、 6 より 大きいので 右の 端を 5 の 位置へ 戻します。 ここで 左の 端が 右の 端を 越えたので、 範囲が 空に なり -1 を 返します。」