閑話二分查找(搜索)

二分查找(搜索)的英文名是 Binary Search荷愕,直譯過來其實應(yīng)該叫二進制搜索衡怀,但這些都不重要,只要知道有這么個英文名就行安疗。

什么是二分查找

二分查找是一種在每次比較之后將查找空間一分為二的算法抛杨。每次需要查找集合中的索引或元素時,都應(yīng)該考慮二分查找荐类。如果集合是無序的怖现,我們需要在應(yīng)用二分查找之前先對其進行排序。
二分查找是計算機科學中最基本玉罐、最有用的算法之一屈嗤。 它描述了在有序集合中搜索特定值的過程。二分查找中使用的術(shù)語有:

  • 目標 Target —— 你要查找的值
  • 索引 Index —— 你要查找的當前位置
  • 左吊输、右指示符 Left饶号,Right —— 我們用來維持查找空間的指標
  • 中間指示符 Mid —— 我們用來應(yīng)用條件來確定我們應(yīng)該向左查找還是向右查找的索引

二分的本質(zhì)

我們平時所說的二分大多指數(shù)組的二分,因為數(shù)組可以隨機訪問嘛璧亚;
不過這種二分實在太狹義了讨韭,二分的本質(zhì)是將問題規(guī)闹牛縮小到一半癣蟋,因此二分和數(shù)據(jù)結(jié)構(gòu)沒有本質(zhì)關(guān)系透硝!
但不同的數(shù)據(jù)結(jié)構(gòu)卻給二分賦予了不同的色彩;
比如:

跳表就是鏈表的二分(比如redis的跳躍表)疯搅;
二叉搜索樹就是樹的二分濒生;
……;

二分查找的三個基本組成部分

二分查找的先決條件是【有序的折半邏輯】幔欧,即每次折半查詢時罪治,有條件區(qū)分出另一半數(shù)據(jù),不一定非得是數(shù)學上的升序降序礁蔗;二分查找一般由三個主要部分組成:

  • 預(yù)處理 —— 如果集合未排序觉义,則進行排序。
  • 二分查找 —— 使用循環(huán)或遞歸在每次比較后將查找空間劃分為兩半浴井。
  • 后處理 —— 在剩余空間中確定可行的候選者晒骇。

二分查找的三種基本模板

模板-I-1
  • 一般用于精確查找值;
  • 結(jié)束條件:L>R;
while ($L <= $R) {
    $mid=$L+floor(($R-$L)/2);//防止溢出
    if ($mid < $target) {
        $L = $mid+1;
    } else if ($mid > $target) {
        $R = $mid-1;
    } else if ($mid == $target) {
        return $mid; //注意,此模板一般直接返回結(jié)果
    } 
}
return null;
模板-II-2
  • 一般用于尋找左邊界磺浙;
  • 結(jié)束條件:L==R洪囤;
while ($L < $R) {
    $mid=$L+floor(($R-$L)/2);//防止溢出
    if ($mid < $target) {
        $L = $mid+1;
    } else if ($mid >= $target) {
        $R = $mid; //注意此處R=mid
    }
}
return $R;//L或R都行,因為結(jié)束條件是L==R;
模板-III
int binarySearch(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left + 1 < right){
        // Prevent (left + right) overflow
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            left = mid;
        } else {
            right = mid;
        }
    }
    // Post-processing:
    // End Condition: left + 1 == right
    if(nums[left] == target) return left;
    if(nums[right] == target) return right;
    return -1;
}

模板 #3 是二分查找的另一種獨特形式:
它用于搜索需要訪問當前索引及其在數(shù)組中的直接左右鄰居索引的元素或條件撕氧。

模板-III 的邊界條件
  • 初始條件:left = 0, right = length-1
  • 終止:left + 1 == right
  • 向左查找:right = mid
  • 向右查找:left = mid

透過小白兔(鼠)試毒問題去看二分的本質(zhì)

盡管上面已經(jīng)說了, 不要將二分法局限于某種數(shù)據(jù)結(jié)構(gòu), 但多數(shù)人還是習慣于狹義的將二分法理解為數(shù)組的二分, 總覺著問題得能具象化為一組數(shù)才可以施展二分大法瘤缩。
實則不然, 上面提到過, 二分的本質(zhì)在于將問題規(guī)模縮小到原來的一半, 所以請看下面這道題:

現(xiàn)在有1000瓶藥水, 其中1瓶是毒藥, 只需一滴就可讓小白兔在24小時內(nèi)死亡; 問伦泥,如何在最短時間內(nèi)用最少的小白兔, 找出這瓶毒藥剥啤?

該題據(jù)說是某大(鵝)廠面試題, 看上去似乎挺簡單:
1000只小兔子, 挨個兒試; 或者, 1只兔子, 一天試一瓶;

不過嘛, 想想也知道答案不是這樣, 要不, 就沒有考你的必要了。
那么不脯,如何巧妙的找到這瓶毒藥呢府怯?
這就要用到本文一直在講的二分法了;乍一看跨新,這題貌似和二分扯不上關(guān)系富腊,如果我們把題目簡化一下,就好理解了域帐。

現(xiàn)在有4瓶藥水, 其中1瓶是毒藥, 只需一滴就可讓小白兔在24小時內(nèi)死亡; 問赘被,如何在最短時間內(nèi)用最少的小白兔, 找出這瓶毒藥?

先套用上面的簡單解法:4只小兔子肖揣,或者1只試4天民假;
發(fā)散你的小思維再想一想,能否再縮短一些龙优?
實際上羊异,這個簡單方案,用不到4只或4天,只需3只或3天即可野舶,因為最后一瓶可以用排除法得到答案易迹;
所以,問題就可以繼續(xù)簡化為:

現(xiàn)在有3瓶藥水, 毒藥可能在里邊也可能不在平道,如何用最小的代價確定它在不在里邊睹欲。

接下來該如何優(yōu)化這個解法呢,也就是一屋,如何把3瓶不相干的藥水二分呢窘疮?
如果你沒有思路,就想想二分法的英文名冀墨,它為什么叫 Binary Search闸衫?
其實就是將數(shù)字轉(zhuǎn)化為二進制吖!聰明的你是不是也想到了呢诽嘉?

現(xiàn)在我們將 1到3號瓶 按二進制進行編號:

01 - 1號瓶
10 - 2號瓶
11 - 3號瓶

它們的共性是什么蔚出,也就一目了然了,每一個數(shù)都由兩位二進制數(shù)構(gòu)成含懊,如果我們把問題分成這么兩類來看:

1身冬、有毒藥水的第1位是否為1;
2岔乔、有毒藥水的第2位是否為1酥筝;

是不是就可以借用二分思路了呢?

根據(jù)這個思路雏门,需要請來兩只小兔子奉獻一下嘿歌,將其編號為1號兔和2號兔,并將3瓶藥水按上面的二進制表達式編號:

1號兔只喂二進制第一位是1的藥水茁影;
2號兔只喂二進制第二位是1的藥水宙帝;

24小時后,如果:
1號兔死亡募闲,說明有毒的是3瓶中的第1瓶步脓;
2號兔死亡,說明有毒的是3瓶中的第2瓶浩螺;

如果1號和2號都沒事兒靴患,說明有毒的是被我們拋棄的那一瓶;為了便于統(tǒng)一觀察要出,可以將被拋棄的那瓶藥水的二進制編號為 00鸳君,轉(zhuǎn)換為十進制即第0號瓶:

01 - 1號瓶
10 - 2號瓶
11 - 3號瓶
00 - 0號(4號)瓶

如此二分優(yōu)化下來,4瓶藥水患蹂,我們只需2只小兔子奉獻或颊,就可在1天內(nèi)找出有毒藥水砸紊;

下面我們把瓶子數(shù)量:
擴展到100瓶;套用二進制思路囱挑,只需7只就可在1天內(nèi)找出有毒藥水醉顽;
再擴展到1000瓶,只需10只就可在1天內(nèi)找出有毒藥水看铆;

聰明的你想到答案了嗎徽鼎?看完這道題盛末,你是否對二分法有了更深入的了解呢弹惦?



提示:
99的二進制表達式為:1100011;
999的二進制表達式為:1111100111;
嚴格來說,原題中的1000瓶解題思路并非是二分法幽邓,稱之為十分法更為貼切(100瓶則應(yīng)稱之為七分法)眼滤,但本質(zhì)都是套用了二分法的思路,將問題規(guī)睦愦龋縮小到原來的十分之一;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嗡贺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鞍帝,老刑警劉巖诫睬,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帕涌,居然都是意外死亡摄凡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門蚓曼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亲澡,“玉大人,你說我怎么就攤上這事纫版〈残鳎” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵其弊,是天一觀的道長癞己。 經(jīng)常有香客問我,道長瑞凑,這世上最難降的妖魔是什么末秃? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮籽御,結(jié)果婚禮上练慕,老公的妹妹穿的比我還像新娘惰匙。我一直安慰自己,他們只是感情好铃将,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布项鬼。 她就那樣靜靜地躺著,像睡著了一般劲阎。 火紅的嫁衣襯著肌膚如雪绘盟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天悯仙,我揣著相機與錄音龄毡,去河邊找鬼。 笑死锡垄,一個胖子當著我的面吹牛沦零,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播货岭,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼路操,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了千贯?” 一聲冷哼從身側(cè)響起屯仗,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搔谴,沒想到半個月后魁袜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡己沛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年慌核,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片申尼。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡垮卓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出师幕,到底是詐尸還是另有隱情粟按,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布霹粥,位于F島的核電站灭将,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏后控。R本人自食惡果不足惜庙曙,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浩淘。 院中可真熱鬧捌朴,春花似錦吴攒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至左驾,卻和暖如春镣隶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诡右。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工安岂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稻爬。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓嗜闻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親桅锄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容