二分查詢的實現及邊界問題討論

2021-10-10 03:18:23 字數 2670 閱讀 3168

二分查詢也稱折半查詢(binary search),它是一種效率較高的查詢方法,前提是資料結構必須先排好序,可以在資料規模的對數時間複雜度內完成查詢。但是,二分查詢要求線性表具有有隨機訪問的特點(例如陣列),也要求線性表能夠根據中間元素的特點推測它兩側元素的性質,以達到縮減問題規模的效果

——leetcode官網

二分查詢是乙個原理比較簡單但是實現起來有很多細節的問題,因此寫點筆記記錄一下。二分查詢實際上是這樣乙個問題,假設有乙個區間[lo,hi],存在乙個節點x或者乙個範圍x,使得[lo,x]上的點具有性質a,[x,hi]上的點具有性質b,我們要查詢的就是x或者x的邊界。如果將性質定義為大於小於關係的話,就是常見的二分查詢,包括普通的整數二分查詢或者查詢數的範圍。我們先將二分查詢分為三個子問題,在乙個值不重複的陣列中尋找特定的數,在有重複值的陣列中尋找數的左邊界和右邊界。

舉個具體例子

注:我們預設用於二分的陣列是從小到大的整數。(定義可能不嚴謹,後續再想想)

二分實際上也是用分治的思想。首先,我們找到陣列a的中間點mid,檢查mid是否是我們要找的target,如果是的話,返回mid,問題結束;如果不是的話,我們就將原範圍劃分為了兩個子範圍,[lo,mid]和[mid+1,hi],如果a[mid]>target,目標就落在[lo,mid],反之就落在[mid+1,hi]。然後我們調整範圍,更新上下邊界,進行遞迴。由於a[mid]這個點已經驗證過了,因此這裡的區間還可以寫成[lo,mid-1]和[mid+1,hi]。

當搜尋的範圍裡沒有元素時,也就是lo>hi演算法終止。

public

class

binarysearch

int res =

binarysearch

(a,target);}

public

static

binarysearch

(int

a,int target)

//a[mid]大於target,target位於左半邊,調整右邊界

else

if(a[mid]

>target)

//a[mid]小於target,target位於右半邊,調整左邊界

else

if(a[mid]

}//沒找到返回-1

return-1;

}}//結果12

3563

2

public

static

intleftbound

(int

a,int target)

else

if(a[mid]

>target)

else

if(a[mid]

}// return lo;

// if (lo == a.length) return -1;

return a[lo]

==target?lo:-1

;//問題4

}

這裡注意幾個問題

1、為什麼這裡是嚴格小於。可以和問題2結合起來看,這裡和第乙個演算法不同,第乙個演算法裡當範圍裡只剩下乙個值的時候是進行驗證然後退出的。但是這裡是對邊界進行更新,如果最後只剩下乙個元素,lo=hi,更新邊界後仍然還有乙個元素,因此會陷入死迴圈。為了避免死迴圈,所以只剩下乙個元素時要退出,那麼最後乙個元素怎麼檢驗呢,這就到了問題4。

2、為什麼是更新邊界。當我們找到和target相等的值的時候,我們需要做的不是返回這個下標,因為我們是要找左邊界範圍。我們現在已經找到了乙個目標值,說明左邊界在[lo,mid]中,mid也可能是邊界,所以我們讓hi=mid。

3、為什麼是mid-1。如果a[mid]>target,那麼mid肯定不是我們要找的邊界,所以可以把mid去掉。但是也可以不去,把等於和大於合併寫成一種情況,邊界更新都是 hi=mid

4、如果查詢範圍裡最後還剩下乙個值怎麼辦?我們進行驗證,如果等於target,說明這是左邊界(因為左邊已經沒有符合要求的值了),否則陣列裡沒有target,返回-1

public

static

intrightbound

(int

a,int key)

else

if(a[mid]

>key)

else

if(a[mid]

}return a[lo]

== key ? lo :-1

;}

1、為什麼要寫lo+hi+1?之前我們每次取mid其實都是下區取整,因為之前求的是左邊界,所以下取整(靠左)並沒有什麼邊界問題,但是求右邊界不行,如果陣列只有兩個數[2,2],求2的右邊界,mid下取整是0,a[0]==2,更新左邊界,lo=0;範圍沒有變化,陷入死迴圈。因此呢,我們要進行上取整,這樣才能跳出去。

2、為啥這裡不能寫lo=mid+1。其實和問題1有關,元素個數少的話可能會導致mid更新後越界。

總結一下,二分查詢其實是乙個問題,查詢特定數和是尋找邊界問題的特殊化。原理很簡單,關鍵就在於處理邊界值的時候能不能考慮到特殊情況。

二分查詢的寫法和區別這篇文章寫的很透徹,是站在開區間和閉區間的角度分析的,可以看一下。

二分查詢中的邊界問題 1, 1, ,

題目描述 統計乙個數字在排序陣列中出現的次數。分析 原來一直對二分法很模糊,對mid 1,還是mid,決定這兩個差不多,今天自己打臉了,控制的不精準就是錯誤。把邊界確定更加準確點,left,end 確定為閉區間,只要不在這個區間,就 1或者 1,不要模糊,不要模糊兩可 class solution ...

二分法查詢的邊界問題

對於不下降序列a,n為序列a元素的個數,key為關鍵字 1.求最小的i,使得a i key,若不存在,則返回 1 int binary search 1 inta,intn int key if a r key returnr return 1 2.求最大的i,使得a i key,若不存在,則返回 ...

二分法的邊界問題

2.求最大的i,使得a i key 對於1的演算法,就是l邊界 左邊界 一直不滿足條件,r邊界在快結束時一定滿足條件,所以最後輸出r,然後區間不斷向左收,右邊界r不動。對於2,就是l左邊界一直不動,縮小右邊界,最後輸出左邊界,要注意的是向上取整。對於不下降序列a,n為序列a元素的個數,key為關鍵字...