🧑🦯
【2分探索】 ~ 境界探索の実装まで ~
はじめに
今回の記事のテーマは2分探索です。競技プログラミングでたまに実装するので、発展した問題まで対応できる考え方・実装を考えます。
2分探索
探索対象が単調列になっている時に使用することができます。計算量がO(log(N))であり、線形探索O(N)と比べて非常に高速です。
問題
配列 li = [1,2,9,18,29,34,44,51,71,98]
があります。
1. ある値x
のインデックスを求めてください。
2. ある値x
以上の最小の数のインデックスを求めてください。
3. ある値x
より大きい最小の数のインデックスを求めてください。
このような問題に対しての実装を考えます。値1つのインデックスを求めるだけではなく、境界を求める問題も考えます。この時、値1つのインデックスを求める際の考え方・実装をできるだけ変えずに、境界を求める実装をしたいと考えます。
考え方
left
とright
には探索が完了したインデックスを保持させる
ポイントはleft
とright
には探索済みのインデックスの値をそれぞれ代入します。イメージは下の図の通りです。left
が4
を保持していることは、「ここまではもう探索済みだよ!」ということを表しています。right
も同様です。
[1, 2, 9, 18, 29, 34, 44, 51, 71, 98]
-1 0 1 2 3 4 5 6 7 8 9 10
^ ^
------探索済み----left right---探索済み---
実装
x
のインデックスを求めてください。
1. ある値def BinarySearch.py(x,li):
left = -1; right = len(li)
while left +1 < right:
mid = (left+right)//2
if li[mid] == x: return mid
elif li[mid] > x: right = mid
elif li[mid] < x: left = mid
return -1
-
while
条件の意味
left + 1 < right
の意味は探索対象区間がなくなるまで、です。条件が偽になるときはleft
とright
が隣り合うとき、すなわち探索対象区間がないときです。 - 値の更新がシンプル
left = mid
やright = mid
で区間を狭めるときの値の更新がシンプルです。
x
以上の最小の数のインデックスを求めてください。
2. ある値def BinarySearch(x,li):
left = -1; right = len(li)
while left + 1 < right:
mid = (left+right)//2
if li[mid] >= x: right = mid
elif li[mid] < x: left = mid
return right
値1つのインデックスを求めるときと、while
の条件、left
とright
の更新という点で同じです。この問題のように境界を求める問題は、ループを最後まで抜けることはないのでそこが違います。
x
より大きい最小の数のインデックスを求めてください。
3. ある値def BinarySearch(x,li):
left = -1; right = len(li)
while left + 1 < right:
mid = (left+right)//2
if li[mid] > x: right = mid
elif li[mid] <= x: left = mid
return right
前の問題とほとんど実装が同じです!違う点はif
の条件です。
最後に
2分探索は基本的なアルゴリズムですが掘り下げると面白いです。これで競技プログラミングで2分探索の問題が出てきたら最高です!
最後まで読んでいただきありがとうございました!
Discussion