二分探索では、ステップごとに探索空間が半分になります。 n 要素のソートされた配列上で、O(log n) 時間でターゲットを見つけます。
def binary_search(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
シンプルですが、二分探索の真の力は、ソートされた配列をはるかに超えています。
二分探索は、範囲にわたって単調条件がある場合には常に機能します。 「配列」は存在する必要さえありません。範囲 [lo, hi] と、ある境界で False から True (またはその逆) を反転する関数が必要です。
Search space: [lo .................. hi]
Condition: F F F F T T T T
^-- answer
配列を検索する代わりに、回答スペースを検索します。 「結果 X を達成できますか?」と尋ねます。 「はい」の場合は、より小さくしてみてください。いいえの場合は、より大きくしてみてください。
ココにはバナナがn山あり、あとh時間あります。彼女が時間内に食べ終わるように最小の食事速度を見つけてください。
def min_speed(piles, h):
lo, hi = 1, max(piles)
while lo < hi:
mid = (lo + hi) // 2
hours = sum((p + mid - 1) // mid for p in piles)
if hours <= h:
hi = mid # speed works, try slower
else:
lo = mid + 1 # too slow, go faster
return lo
回答スペースは [1, max(piles)] で、条件は単調です。速度が高いほど、常に時間が短くなります。
いくつかのピボットで回転されたソートされた配列: [4, 5, 6, 7, 0, 1, 2]。半分は常に並べ替えられます。 mid と lo を比較してどちらの半分かを決定し、ターゲットがソートされた半分に該当するかどうかを確認します。
ログイン ディスカッションに参加
[4, 5, 6, 7, 0, 1, 2]
L M R
Left half [4..7] is sorted.
Target 1 not in [4..7] → search right.
回転ソート配列 [3,4,5,1,2] では、mid=2 (値 5) の場合、どちらの半分がソートされますか?
最初の出現を見つけるには、ターゲットに到達したら止まらず、hi = midを設定して左に検索し続けます。 最後については、lo = mid + 1を設定して右を検索します。
このペアの検索では、ターゲットの 数 も得られます: last - first + 1。
隣接する両方の要素よりも大きい要素。ソートされていない配列でも二分探索は機能します。nums[mid] < nums[mid + 1]の場合、ピークは右側にあります。それ以外の場合は左側です。 O(log n)。
行が並べ替えられており、各行の最初の要素が前の要素の最後の要素より大きい場合、行列は m × n 要素の単一の並べ替えられた配列として扱われます。インデックス k を行 k // n、列 k % n にマップします。
x * x ≤ n の中で最大の整数 x を見つけます。検索スペース: [0, n]。答えに対する古典的な二分探索。
def sqrt(n):
lo, hi = 0, n
while lo <= hi:
mid = (lo + hi) // 2
if mid * mid <= n:
lo = mid + 1
else:
hi = mid - 1
return hi
「分割配列の最大合計」や「D 日以内に荷物を発送できる能力」などの問題では、最悪のケースを最小限に抑えることが求められます。答えは単調です。容量 C が機能する場合、C+1 も機能します。 C の二分探索。
「D 日で荷物を発送できる容量」の場合、二分探索の検索空間はどれくらいですか?
lo, hi = min_possible, max_possible
while lo < hi:
mid = (lo + hi) // 2
if condition(mid):
hi = mid # mid works, try smaller
else:
lo = mid + 1 # mid fails, need larger
return lo
最初の True を求めるか 最後の True を求めるかに応じて、hi = mid 対 lo = mid を調整します。
O(n) の実現可能性チェックを伴うサイズ S の応答空間での二分探索の時間計算量はどれくらいですか?