一次教你搞懂二分查找,算法學(xué)起來可以更直觀瑟押!

前兩天去公司應(yīng)聘搀捷,還沒等我開始自我介紹,面試官上來就要手撕代碼勉耀。題目是這樣的 :

給定一個排序數(shù)組和一個目標值指煎,在數(shù)組中找到目標值蹋偏,并返回其索引便斥。如果目標值不存在于數(shù)組中至壤,返回它將會被按順序插入的位置。
請必須使用時間復(fù)雜度為 O(log n) 的算法枢纠。
示例:
輸入: nums = [1,3,5,6], target = 5
輸出: 2

題目雖然雖然很基礎(chǔ)像街,但是要求時間復(fù)雜度為 O(log n) 。那么肯定就得用二分查找的方法去做了晋渺,下面就用漫畫圖解的形式帶大家一起回顧一下二分查找镰绎。

二分查找

下面的示例說明了二分查找的工作原理。我隨便想一個1~100的數(shù)字木西。

你的目標是以最少的次數(shù)猜到這個數(shù)字畴栖。你每次猜測后,我會說小了八千、大了或?qū)α恕?br> 假設(shè)你從1開始依次往上猜吗讶,猜測過程會是這樣。


這是簡單查找恋捆,更準確的說法是傻找照皆。每次猜測都只能排除一個數(shù)字。如果我想的數(shù)字是99沸停,你得猜99次才能猜到膜毁!

更佳的查找方式

下面是一種更佳的猜法。從 50 開始愤钾。

小了瘟滨,但排除了一半的數(shù)字!至此能颁,你知道1~50都小了室奏。接下來,你猜 75劲装。

大了胧沫,那余下的數(shù)字又排除了一半!使用二分查找時占业,你猜測的是中間的數(shù)字绒怨,從而每次都將余下的數(shù)字排除一半。接下來谦疾,你猜 63(50和75中間的數(shù)字)南蹂。

這就是二分查找,你學(xué)習(xí)了第一種算法念恍!每次猜測排除的數(shù)字個數(shù)如下六剥。

不管我心里想的是哪個數(shù)字晚顷,你在 7 次之內(nèi)都能猜到,因為每次猜測都將排除很多數(shù)字疗疟!

假設(shè)你要在字典中查找一個單詞该默,而該字典包含 240 000 個單詞,你認為每種查找最多需要多少步策彤?

如果要查找的單詞位于字典末尾栓袖,使用簡單查找將需要 240 000 步。使用二分查找時店诗,每次排除一半單詞裹刮,直到最后只剩下一個單詞。

因此庞瘸,使用二分查找只需 18 步——少多了捧弃!一般而言,對于包含n個元素的列表擦囊,用二分查找最多需要 log2n 步违霞,而簡單查找最多需要 n 步。

算法樣例

下面來看看如何編寫執(zhí)行二分查找的Python代碼霜第。這里的代碼示例使用了數(shù)組葛家。如果你不熟悉數(shù)組,也不用擔(dān)心泌类。你只需知道癞谒,可將一系列元素存儲在一系列相鄰的桶(bucket),即數(shù)組中刃榨。這些桶從0開始編號:第一個桶的位置為#0弹砚,第二個桶為#1,第三個桶為#2枢希,以此類推桌吃。

函數(shù)binary_search接受一個有序數(shù)組和一個元素。如果指定的元素包含在數(shù)組中苞轿,這個函數(shù)將返回其位置茅诱。你將跟蹤要在其中查找的數(shù)組部分——開始時為整個數(shù)組。

你每次都檢查中間的元素搬卒。

如果猜的數(shù)字小了瑟俭,就相應(yīng)地修改low。

如果猜的數(shù)字大了契邀,就修改high摆寄。完整的代碼如下。

def binary_search(list, item):
    # low和high用于跟蹤要在其中查找的列表部分
    low = 0
    high = len(list) - 1

    # 只要范圍沒有縮小到只包含一個元素
    while low <= high:
        mid = (low + high) // 2  # 檢查中間的元素
        guess = list[mid]
        if guess == item:  # 找到了元素
            return mid
        if guess > item:  # 猜的數(shù)字大了
            high = mid - 1
        else:  # 猜的數(shù)字小了
            low = mid + 1

    return None  # 沒有指定的元素

回到面試題

給定一個排序數(shù)組和一個目標值,在數(shù)組中找到目標值微饥,并返回其索引逗扒。如果目標值不存在于數(shù)組中,返回它將會被按順序插入的位置欠橘。
請必須使用時間復(fù)雜度為 O(log n) 的算法矩肩。
輸入: nums = [1,3,5,6], target = 5
輸出: 2

那么針對這道題,直接套用二分法即可简软,即不斷用二分法逼近查找第一個大于等于target的下標 蛮拔。我們寫出的二分查找算法就是這樣的:

def searchInsert(nums, target):
    left, right = 0, len(nums)
    while (left < right):
        # 下面這樣寫是考慮大數(shù)情況下避免溢出
        mid = (right - left) // 2 + left
        if target <= nums[mid]:
            right = mid
        else:
            left = mid + 1
    return left

算法學(xué)習(xí)心得

相信大家通過上面這種圖解的方式很輕松就能掌握二分查找的原理述暂。這是《算法圖解》中的一個例子痹升,這是一本能夠像小說一樣有趣的算法入門書

除了二分查找以外畦韭,本書還介紹了選擇排序疼蛾、遞歸快速排序艺配、散列表察郁、廣度優(yōu)先搜索狄克斯特拉算法转唉、貪婪算法皮钠、動態(tài)規(guī)劃K最近鄰算法等赠法。本書所有的示例代碼都是使用Python 2.7編寫的麦轰。書中在列出代碼時使用了等寬字體。有些代碼還進行了標注砖织,旨在突出重要的概念款侵。

如果你是剛?cè)腴T的同學(xué),非常建議從類似這樣的簡單算法書開始學(xué)習(xí)侧纯,切記不要一上來就像一口吃個胖子新锈,路還是得一步一步走。

如果你覺得這本書過于簡單眶熬,還可以看一下普林斯頓算法紅寶書《算法》妹笆,這本書是風(fēng)靡全世界近 40 年的算法經(jīng)典。很多大學(xué)都拿它當(dāng)作教材娜氏,該書非常系統(tǒng)拳缠、全面、嚴謹牍白,提供了實際代碼脊凰,而且這些 Java 代碼實現(xiàn)采用了模塊化的編程風(fēng)格,讀者可以方便地加以改造。

除了看書以外狸涌,還應(yīng)該加上實戰(zhàn)練手切省。在具備一定的算法基礎(chǔ)以后,就可以上leetcode開始刷題了帕胆。我是按照某一類別的題型朝捆,由易到難,循序漸進懒豹,以此來鞏固對算法的理解芙盘,并且提高自己的編程能力。

最后再送給大家一句 Linux 的創(chuàng)始人 Linus Torvalds 的話脸秽,“Talk is cheap. Show me the code.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末儒老,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子记餐,更是在濱河造成了極大的恐慌驮樊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件片酝,死亡現(xiàn)場離奇詭異囚衔,居然都是意外死亡,警方通過查閱死者的電腦和手機雕沿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門练湿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人审轮,你說我怎么就攤上這事肥哎。” “怎么了断国?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵贤姆,是天一觀的道長。 經(jīng)常有香客問我稳衬,道長霞捡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任薄疚,我火速辦了婚禮碧信,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘街夭。我一直安慰自己砰碴,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布板丽。 她就那樣靜靜地躺著呈枉,像睡著了一般趁尼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猖辫,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天酥泞,我揣著相機與錄音,去河邊找鬼啃憎。 笑死芝囤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辛萍。 我是一名探鬼主播悯姊,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贩毕!你這毒婦竟也來了悯许?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耳幢,失蹤者是張志新(化名)和其女友劉穎岸晦,沒想到半個月后欧啤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睛藻,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年邢隧,在試婚紗的時候發(fā)現(xiàn)自己被綠了店印。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡倒慧,死狀恐怖按摘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纫谅,我是刑警寧澤炫贤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站付秕,受9級特大地震影響兰珍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜询吴,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一掠河、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猛计,春花似錦唠摹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春藕赞,著一層夾襖步出監(jiān)牢的瞬間苛秕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工找默, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留艇劫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓惩激,卻偏偏與公主長得像店煞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子风钻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

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