C# 二分探索法で配列のなかから最も近い値を取得する
binary-search-nearest-value

二分探索法はソート済みの配列において、検索する間隔を半分に分割しながらデータを探し出すアルゴリズムです。先頭からひとつずつ比較して探し出すよりも高速で必要なデータを探しだすことができるようになります。もし配列の長さが100,000の場合、先頭から調べていくと最大で100,000回の比較が必要ですが、二分探索法だと17回の比較でよくなるのです。

二分探索法を使えば全探索をしなくても効率的に値を探すことができるようになります。

配列内にある最も近い値はどれか

配列のなかにある数と同じものはあるか?ない場合、もっとも近い数はどれかを探すときも二分探索法は使えます。

配列の要素でtargetにもっとも近いものを探すサンプルプログラムとしてよく見かけるものです。targetとの差の絶対値でもっとも小さくなるものを取得して、targetとの差の絶対値がこれと一致するものを探すという二段階作戦です。

もし配列の要素数がそんなに多くなくtargetもひとつだけというのであればこれで問題はありません。

ただ配列の要素数が長くてtargetが複数ある場合は二分探索法を使うと時間を短縮することができます。

これはtargetよりも大きな値と小さな値でもっとも近いものを取得するコードです。

応用例

これはAtCoderの競プロ典型 90 問のなかのひとつ 007 – CP Classes ですが、これは二分探索法が有効です。

ABC 競技プログラミング塾には N 個のクラスがあり、番号 i (1≦i≦N) のクラスはレーティング A[i]の生徒を対象としています。

今、Q 人の生徒がこの塾に入塾しようとしています。 番号 j (1≦j≦Q) の生徒のレーティングは B[j]です。 各生徒は自分に合わないレベルのクラスに行くと不満になります。 各生徒について、その不満度は対象レーティング a と自分のレーティング b の差の絶対値、すなわち |a-b| で定義されます。

j=1,2,3,…,Q それぞれについて生徒の不満度として考えられる最小値を求めてください。

1≦N≦300000, 1≦Q≦300000 という条件なので、長い配列のなかを何度も配列内にある最も近い値を探す処理を繰り返さないといけないので、これは二分探索法でやらないとタイムオーバーになってしまいます。