序文
長さ1000メートルのパイプがあり、未知の場所に穴があるとします。この穴を見つけたい場合、どのように探す必要がありますか?
実際のアプリケーションでは、価格の高い順に排出する、対象物の大きさに応じた連続排出、上記のパイプライン検査などの問題など、さまざまな場所で順次排出のシーケンスを見ることができます。
条件を満たす特定の値を見つける必要がある場合、順番に検索するために多くの不要な検索が必要になります。現時点では、2つのポイントを使用することで多くのコストを節約できます。
上記の1000メートルのパイプラインに直面して、二分メカニズムを採用することができ、毎回、次の検索のためにできるだけ多くのパイプラインを除外します。
二分探索
テンプレート検索プロセスをよりよく理解するために、最初に簡単な例を挙げましょう
順序付きリストで、要素54を見つけます
最初のラウンド
l = 0
r = 13
mid = (l + r) / 2 = 6
現時点では、midが指す数は54未満であるため、54はmidとrの間にあり、lからmidまでのすべてのデータを除外できます。
第2ラウンド
l = mid + 1 = 7
r = 13(不变)
mid = (l + r) / 2 = 10
このとき、midが指す数は54より大きいので、54はlとmidの間にあり、midからrまでのすべてのデータを除外できます。
第3ラウンド
l = 7(不变)
r = mid = 10
mid = (l + r) / 2 = 8
このとき、midが指す数は54で、検索は終了します。
時間計算量:O(logN)
スペースの複雑さ:O(1)
ここでの複雑さは実際には平均の複雑さです。アルゴリズムのログレベルの時間計算量は分割統治の概念を使用しています。このベースは分割統治の複雑さによって決定されます。つまり、バイナリ検索メカニズムが使用されます。その場合、そのベースは2です。
テンプレート1
ある上司のテンプレートを参考に、学習しやすいように説明しました
間隔[l, r]
がに分割され[l, mid]
、[mid + 1, r]
その更新操作中にがr = mid
またはl = mid + 1
;の場合、計算された中間に1を追加する必要はありません。
コードテンプレート
function search_1(l, r)
{
while (l < r)
{
var mid = l + r >> 1;
if(/*mid找到*/) return mid;
if (check(mid)) r = mid;
else l = mid + 1;
}
return false;
}
-
なぜ
l < r
それを終わらせる条件なのですか?回答:上の写真によると、ターゲットが見つからない場合は、左右のポインターが重なり、重なり合うと終了します。
-
なぜそれを使用
l + r >> 1
するのですか、他の方法はありますか?解決策:JavaScriptでは、10進整数を削除する方法
parseInt()
とMath.floor()
、>>
変位可能な方法が採用されているため、右の矢印は1を示しているように見えます。つまり、2で割ってから丸められMath.floor((l + r) / 2)
ますが、今回は同じ効果があります。
テンプレート2
間隔[l, r]
がに分割され[l, mid - 1]
、[mid, r]
その更新操作中にがr = mid - 1
またはである場合l = mid
、この時点で無限ループを防ぐために、コンピューティングmid
は1を追加する必要があります。
function search_2(l, r)
{
while (l < r)
{
var mid = l + r + 1 >> 1;
if(/*mid找到*/) return mid;
if (check(mid)) l = mid;
else r = mid - 1;
}
return false;
}
使用する
上記の配列でも、テンプレート1を使用して54を検索します
var array = [1, 2, 4, 9, 11, 15, 20, 25, 54, 90, 100, 110, 111, 242];
function search_1(nums, target) {
if (target == null || nums.length == 0) return false;
var l = 0,
r = nums.length - 1;
while (l < r) {
var mid = (l + r) >> 1;
if(target == nums[mid]) return mid;
if (target < nums[mid]) {
r = mid;
} else {
l = mid + 1;
}
}
return false;
}
function search_2(nums, target) {
if (target == null || nums.length == 0) return false;
var l = 0,
r = nums.length - 1;
while (l < r) {
var mid = (l + r + 1) >> 1;
if(target == nums[mid]) return mid;
if(target > nums[mid]) l = mid;
else r = mid - 1;
}
return false;
}
総括する
二分探索では、データが正常である必要があります。
- 中央の位置がターゲットと比較され、等しいかどうかが検出されます。それ以外の場合は、元のテーブルを2つのテーブルに分割します
l > r
時間が見つからないとき。