當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]今天給大家?guī)?lái)的是二分查找及其變種的總結(jié),大家一定要看到最后呀,非常非常用心的一篇文章,廢話不多說(shuō),讓導(dǎo)演幫我們把鏡頭切到袁記菜館吧!

今天給大家?guī)?lái)的是二分查找及其變種的總結(jié),大家一定要看到最后呀,非常非常用心的一篇文章,廢話不多說(shuō),讓導(dǎo)演幫我們把鏡頭切到袁記菜館吧!

袁記菜館內(nèi)。。。。

店小二:掌柜的,您進(jìn)貨回來(lái)了呀,喲!今天您買這魚(yú)挺大呀!

袁廚:那是,這是我今天從咱們江邊買的,之前一直去菜市場(chǎng)買,那里的老貴了,你猜猜我今天買的多少錢一條。

店小二:之前的魚(yú),30個(gè)銅板一條,今天的我猜26個(gè)銅板。

袁廚:貴了。

店小二:還貴呀!那我猜20個(gè)銅板!

袁廚:還是貴了。

店小二:15個(gè)銅板。

袁廚:便宜了

店小二:18個(gè)銅板

袁廚:恭喜你猜對(duì)了

上面的例子就用到了我們的二分查找思想,如果你玩過(guò)類似的游戲,那二分查找理解起來(lái)肯定很輕松啦,下面我們一起征服二分查找吧!

二分查找

二分查找也稱折半查找(Binary Search),是一種在有序數(shù)組中查找某一特定元素的搜索算法。我們可以從定義可知,運(yùn)用二分搜索的前提是數(shù)組必須是有序的,這里需要注意的是,我們的輸入不一定是數(shù)組,也可以是數(shù)組中某一區(qū)間的起始位置和終止位置

通過(guò)上面二分查找的定義,我們知道了二分查找算法的作用及要求,那么該算法的具體執(zhí)行過(guò)程是怎樣的呢?

下面我們通過(guò)一個(gè)例子來(lái)幫助我們理解。我們需要在 nums ?數(shù)組中,查詢?cè)?8 的索引

面試前必知必會(huì)的二分查找及其變種

(1)我們需要定義兩個(gè)指針?lè)謩e指向數(shù)組的頭部及尾部,這是我們?cè)谡麄€(gè)數(shù)組中查詢的情況,當(dāng)我們?cè)跀?shù)組某一區(qū)間進(jìn)行查詢時(shí),可以輸入數(shù)組,起始位置,終止位置進(jìn)行查詢。

面試前必知必會(huì)的二分查找及其變種

(2)找出mid,該索引為mid =(left + right)/ 2,但是這樣寫(xiě)有可能溢出,所以我們需要改進(jìn)一下寫(xiě)成mid = left +(right - left)/ 2 或者 ?left + ((right - left ) >> 1) ?兩者作用是一樣的,都是為了找到兩指針的中索引,使用位運(yùn)算的速度更快。那么此時(shí)的 mid = 0 + (8-0) / 2 = 4

面試前必知必會(huì)的二分查找及其變種

(3)此時(shí)我們的 mid = 4,nums[mid] = 6 < target,那么我們需要移動(dòng)我們的 left 指針,讓left = mid + 1,下次則可以在新的 left 和 right 區(qū)間內(nèi)搜索目標(biāo)值,下圖為移動(dòng)前和移動(dòng)后

面試前必知必會(huì)的二分查找及其變種

(4)我們需要在 left 和 right 之間計(jì)算 mid 值,mid = 5 + (8 - 5)/ 2 ?= 6 然后將 nums[mid] 與 target 繼續(xù)比較,進(jìn)而決定下次移動(dòng)left 指針還是 right 指針,見(jiàn)下圖

面試前必知必會(huì)的二分查找及其變種

(5)我們發(fā)現(xiàn) nums[mid] > target,則需要移動(dòng)我們的 right 指針, 則 right = mid - 1;則移動(dòng)過(guò)后我們的 left 和 right 會(huì)重合,這里是我們的一個(gè)重點(diǎn)大家需要注意一下,后面會(huì)對(duì)此做詳細(xì)敘述。

面試前必知必會(huì)的二分查找及其變種

(6)我們需要在 left 和 right 之間繼續(xù)計(jì)算 mid 值,則 mid = 5 +(5 - 5)/ 2 = 5 ,見(jiàn)下圖,此時(shí)我們將 nums[mid] 和 target 比較,則發(fā)現(xiàn)兩值相等,返回 mid 即可 ,如果不相等則跳出循環(huán),返回 -1。

面試前必知必會(huì)的二分查找及其變種

二分查找的執(zhí)行過(guò)程如下

1.從已經(jīng)排好序的數(shù)組或區(qū)間中,取出中間位置的元素,將其與我們的目標(biāo)值進(jìn)行比較,判斷是否相等,如果相等則返回。

2.如果 nums[mid] ?和 target 不相等,則對(duì) nums[mid] 和 target 值進(jìn)行比較大小,通過(guò)比較結(jié)果決定是從 mid左半部分還是右半部分繼續(xù)搜索。

如果 target > nums[mid] 則右半?yún)^(qū)間繼續(xù)進(jìn)行搜索,即 left = mid + 1;?target < ?nums[mid] 則在左半?yún)^(qū)間繼續(xù)進(jìn)行搜索,即 right = mid -1;

動(dòng)圖解析

面試前必知必會(huì)的二分查找及其變種


下面我們來(lái)看一下二分查找的代碼,可以認(rèn)真思考一下 if 語(yǔ)句的條件,每個(gè)都沒(méi)有簡(jiǎn)寫(xiě)。

面試前必知必會(huì)的二分查找及其變種

二分查找的思路及代碼已經(jīng)理解了,那么我們來(lái)看一下實(shí)現(xiàn)時(shí)容易出錯(cuò)的地方

1.計(jì)算 mid 時(shí) ,不能使用 (left + right )/ 2,否則有可能會(huì)導(dǎo)致溢出

2.while ?(left < = right) ?注意括號(hào)內(nèi)為 left <= right ,而不是 left < right ,我們繼續(xù)回顧剛才的例子,如果我們?cè)O(shè)置條件為 left ?< ?right 則當(dāng)我們執(zhí)行到最后一步時(shí),則我們的 left 和 right 重疊時(shí),則會(huì)跳出循環(huán),返回 -1,區(qū)間內(nèi)不存在該元素,但是不是這樣的,我們的 left 和 right 此時(shí)指向的就是我們的目標(biāo)元素 ,但是此時(shí) left = right 跳出循環(huán)

3.left = mid + 1,right = mid - 1 而不是 left = mid 和 right = mid。我們思考一下這種情況,見(jiàn)下圖,當(dāng)我們的target 元素為 16 時(shí),然后我們此時(shí) left = 7 ,right = 8,mid = left + (right - left) = 7 + (8-7) = 7,那如果設(shè)置 left = mid 的話,則會(huì)進(jìn)入死循環(huán),mid ?值一直為7 。

面試前必知必會(huì)的二分查找及其變種


下面我們來(lái)看一下二分查找的遞歸寫(xiě)法

面試前必知必會(huì)的二分查找及其變種

例題:

題目描述

題目來(lái)源:leetcode35搜索插入位置

給定一個(gè)排序數(shù)組和一個(gè)目標(biāo)值,在數(shù)組中找到目標(biāo)值,并返回其索引。如果目標(biāo)值不存在于數(shù)組中,返回它將會(huì)被按順序插入的位置。

你可以假設(shè)數(shù)組中無(wú)重復(fù)元素。

示例 1:

輸入: [1,3,5,6], 5 輸出: 2

示例 2:

輸入: [1,3,5,6], 2 輸出: 1

示例 3:

輸入: [1,3,5,6], 7 輸出: 4

示例 4:

輸入: [1,3,5,6], 0 輸出: 0

題目解析

這個(gè)題目完全就和咱們的二分查找一樣,只不過(guò)有了一點(diǎn)改寫(xiě),那就是將咱們的返回值改成了 left,具體實(shí)現(xiàn)過(guò)程見(jiàn)下圖

面試前必知必會(huì)的二分查找及其變種

面試前必知必會(huì)的二分查找及其變種


二分查找變種一

上面我們說(shuō)了如何使用二分查找在數(shù)組或區(qū)間里查出特定值的索引位置。但是我們剛才數(shù)組里面都沒(méi)有重復(fù)值,查到返回即可,那么我們思考一下下面這種情況

面試前必知必會(huì)的二分查找及其變種

此時(shí)我們數(shù)組里含有多個(gè) 5 ,我們查詢是否含有 5 可以很容易查到,但是我們想獲取第一個(gè) 5 和 最后一個(gè) 5 的位置應(yīng)該怎么實(shí)現(xiàn)呢?哦!我們可以使用遍歷,當(dāng)查詢到第一個(gè) 5 時(shí),我們?cè)O(shè)立一個(gè)指針進(jìn)行定位,然后到達(dá)最后一個(gè) 5 時(shí)返回,這樣我們就能求的第一個(gè)和最后一個(gè)五了?因?yàn)槲覀冞@個(gè)文章的主題就是二分查找,我們可不可以用二分查找來(lái)實(shí)現(xiàn)呢?當(dāng)然是可以的。

題目描述

題目來(lái)源:leetcode 34在排序數(shù)組中查找元素的第一個(gè)和最后一個(gè)位置


給定一個(gè)按照升序排列的整數(shù)數(shù)組 nums,和一個(gè)目標(biāo)值 target。找出給定目標(biāo)值在數(shù)組中的開(kāi)始位置和結(jié)束位置。

如果數(shù)組中不存在目標(biāo)值 target,返回 [-1, -1]。

示例 1:

輸入:nums = [5,7,7,8,8,10], target = 8 輸出:[3,4]

示例 2:

輸入:nums = [5,7,7,8,8,10], target = 6 輸出:[-1,-1]

示例 3:

輸入:nums = [], target = 0 輸出:[-1,-1]

題目解析

這個(gè)題目很容易理解,我們?cè)谏厦嬲f(shuō)了如何使用遍歷解決該題,但是這個(gè)題目的目的就是讓我們使用二分查找,我們來(lái)逐個(gè)分析,先找出目標(biāo)元素的下邊界,那么我們?nèi)绾握业侥繕?biāo)元素的下邊界呢?

我們來(lái)重點(diǎn)分析一下剛才二分查找中的這段代碼

面試前必知必會(huì)的二分查找及其變種

我們只需在這段代碼中修改即可,我們?cè)賮?lái)剖析一下這塊代碼,nums[mid] == target 時(shí)則返回,nums[mid] < target 時(shí)則移動(dòng)左指針,在右區(qū)間進(jìn)行查找, nums[mid] ?> ?target時(shí)則移動(dòng)右指針,在左區(qū)間內(nèi)進(jìn)行查找。

那么我們思考一下,如果此時(shí)我們的 nums[mid] = target ,但是我們不能確定 mid 是否為該目標(biāo)數(shù)的左邊界,所以此時(shí)我們不可以返回下標(biāo)。例如下面這種情況。面試前必知必會(huì)的二分查找及其變種

此時(shí) mid = 4 ,nums[mid] = 5,但是此時(shí)的 mid 指向的并不是第一個(gè) 5,所以我們需要繼續(xù)查找 ,因?yàn)槲覀円?span style="letter-spacing: 0px;">的是數(shù)的下邊界,所以我們需要在 mid 的值的左區(qū)間繼續(xù)尋找 5 ,那我們應(yīng)該怎么做呢?

我們只需在target <= nums[mid] 時(shí),讓 right = mid - 1即可,這樣我們就可以繼續(xù)在 mid 的左區(qū)間繼續(xù)找 5 。是不是聽(tīng)著有點(diǎn)繞,我們通過(guò)下面這組圖進(jìn)行描述。

面試前必知必會(huì)的二分查找及其變種

面試前必知必會(huì)的二分查找及其變種


其實(shí)原理很簡(jiǎn)單,就是我們將小于和等于合并在一起處理,當(dāng) target <= nums[mid] 時(shí),我們都移動(dòng)右指針,也就是 right ?= mid -1,還有一個(gè)需要注意的就是,我們計(jì)算下邊界時(shí)最后的返回值為 left ,當(dāng)上圖結(jié)束循環(huán)時(shí),left = 3,right = 2,返回 left 剛好時(shí)我們的下邊界。我們來(lái)看一下求下邊界的具體執(zhí)行過(guò)程。

動(dòng)圖解析

面試前必知必會(huì)的二分查找及其變種

計(jì)算下邊界代碼

面試前必知必會(huì)的二分查找及其變種

計(jì)算上邊界時(shí)算是和計(jì)算上邊界時(shí)條件相反,

計(jì)算下邊界時(shí),當(dāng) ?target <= nums[mid] ?時(shí),right = mid -1;target > nums[mid] 時(shí),left = mid + 1;

計(jì)算上邊界時(shí),當(dāng) ?target < nums[mid] 時(shí),right = mid -1; target >= nums[mid] 時(shí) left = mid + 1;剛好和計(jì)算下邊界時(shí)條件相反,返回right。

計(jì)算上邊界代碼

面試前必知必會(huì)的二分查找及其變種

題目完整代碼

面試前必知必會(huì)的二分查找及其變種

二分查找變種二

我們?cè)谏厦娴淖兎N中,描述了如何找出目標(biāo)元素在數(shù)組中的上下邊界,然后我們下面來(lái)看一個(gè)新的變種,如何從數(shù)組或區(qū)間中找出第一個(gè)大于或最后一個(gè)小于目標(biāo)元素的數(shù)的索引,例 nums = {1,3,5,5,6,6,8,9,11} ?我們希望找出第一個(gè)大于 5的元素的索引,那我們需要返回 4 ,因?yàn)?5 的后面為 6,第一個(gè) 6 的索引為 4,如果希望找出最后一個(gè)小于 6 的元素,那我們則會(huì)返回 3 ,因?yàn)?6 的前面為 5 最后一個(gè) 5 的索引為 3。好啦題目我們已經(jīng)了解,下面我們先來(lái)看一下如何在數(shù)組或區(qū)間中找出第一個(gè)大于目標(biāo)元素的數(shù)吧。

找出第一個(gè)大于目標(biāo)元素的數(shù),大概有以下幾種情況

面試前必知必會(huì)的二分查找及其變種

1.數(shù)組包含目標(biāo)元素,找出在他后面的第一個(gè)元素

2.目標(biāo)元素不在數(shù)組中,且數(shù)組中的所有元素都大于它,那么我們此時(shí)返回?cái)?shù)組的第一個(gè)元素即可

3.目標(biāo)元素不在數(shù)組中,數(shù)組內(nèi)的部分元素大于它,此時(shí)我們需要返回第一個(gè)大于他的元素

4.目標(biāo)元素不在數(shù)組中,且數(shù)組中的所有元素都小于它,那么我們此時(shí)沒(méi)有查詢到,返回 -1 即可。

既然我們已經(jīng)分析完所有情況,那么這個(gè)題目對(duì)咱們就沒(méi)有難度了,下面我們描述一下案例的執(zhí)行過(guò)程

nums = {1,3,5,5,6,6,8,9,11} ? ? ?target = 7

上面的例子中,我們需要找出第一個(gè)大于 7 的數(shù),那么我們的程序是如何執(zhí)行的呢?

面試前必知必會(huì)的二分查找及其變種

上面的例子我們已經(jīng)弄懂了,那么我們看一下,當(dāng) target = 0時(shí),程序應(yīng)該怎么執(zhí)行呢?

面試前必知必會(huì)的二分查找及其變種

OK!我們到這一步就能把這個(gè)變種給整的明明白白的了,下面我們看一哈程序代碼吧,也是非常簡(jiǎn)單的。

面試前必知必會(huì)的二分查找及其變種

通過(guò)上面的例子我們應(yīng)該可以完全理解了那個(gè)變種,下面我們繼續(xù)來(lái)看以下這種情況,那就是如何找到最后一個(gè)小于目標(biāo)數(shù)的元素。還是上面那個(gè)例子

nums = {1,3,5,5,6,6,8,9,11} ? ? ?target = 7

查找最后一個(gè)小于目標(biāo)數(shù)的元素,比如我們的目標(biāo)數(shù)為 7 ,此時(shí)他前面的數(shù)為 6,最后一個(gè) 6 的索引為 5,此時(shí)我們返回 5 即可,如果目標(biāo)數(shù)元素為 12,那么我們最后一個(gè)元素為 11,仍小于目標(biāo)數(shù),那么我們此時(shí)返回 8,即可。這個(gè)變種其實(shí)算是上面變種的相反情況,上面的會(huì)了,這個(gè)也完全可以搞定了,下面我們看一下代碼吧。

面試前必知必會(huì)的二分查找及其變種

哎嘛寫(xiě)著寫(xiě)著咋就那么多了,太長(zhǎng)了大家就不愛(ài)看啦,然后我們一起思考一下如果數(shù)組不完全有序我們可以用二分查找嗎?這個(gè)就放在下篇說(shuō)吧,咱們下篇見(jiàn)呀!

特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒(méi)關(guān)注的小伙伴,可以長(zhǎng)按關(guān)注一下:

面試前必知必會(huì)的二分查找及其變種

面試前必知必會(huì)的二分查找及其變種

面試前必知必會(huì)的二分查找及其變種

長(zhǎng)按訂閱更多精彩▼

面試前必知必會(huì)的二分查找及其變種

如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉