二分查詢可以學習如何上下界問題非常有幫助。
首先討論統一介面的情況,便於實現其他演算法的版本。
這裡使用兩種思路去討論演算法的實現形式,第一種以「減而治之」的策略實現並從查詢行為平衡度等方面對演算法進行改進,第二種直接從通過規則的討論直接討論演算法組成,各層判斷。
語義定義:在有序向量的區間[l,h)內查詢元素v,返回秩最大者。
語義定義:在有序向量的區間[l,h]內查詢元素v,返回秩最大者。
upper_bound 當v存在時返回它出現的最後乙個位置的後面乙個位置。如果不存在,返回這樣乙個下標,在此處插入e,原來元素全部往後移動乙個位置,後序列仍然有序。
lower_bound 當v存在時返回它出現的第乙個位置。如果不存在,返回這樣乙個下標,在此處插入e,原來元素全部往後移動乙個位置,後序列仍然有序。
之所以有如上區別,在於實現時候邏輯的統一性。請看下表
首先討論上述情況下迴圈體的三種情況。
設lo為左邊界,hi為右邊界,mid = (lo+hi)/2,那麼,根據mid的取值,分三種情況:
a[mid] == v,中間值等於v,而要求的是最後一次出現的v。最後出現的v值一定在mid的右邊或者就是mid位置的這個值,所以我們應該調整左邊界,lo = mid,區間變為[mid,hi]
a[mid] < v,說明v如果在陣列中,應該出現在mid右側,則調整左邊界,l = mid + 1,區間變為[mid+1,hi]
a[mid] > v,說明v如果在陣列中,應該出現在mid左側,則調整右邊界,v如果不在陣列中,可能出現在mid的位置上,h=mid,區間變為[lo,mid]
a[mid] == v,中間值等於v,而要求的是最後一次出現的v。最後出現的v值一定在mid的右邊或者就是mid位置的這個值,所以我們應該調整左邊界,lo = mid,區間變為[mid,hi]
左閉右閉區間,upper_bound
a[m]=v 至少已經找到乙個,而右邊可能還有,因此區間變為[m,h]
a[m]>v 所求位置不可能在右邊,但有可能是m,因此區間變為[l,m]
a[m]左閉右閉區間,lower_bound
a[m]=v 至少已經找到乙個,而左邊可能還有,因此區間變為[l,m]
a[m]>v 所求位置不可能在右邊,但有可能是m,因此區間變為[l,m]
a[m]左閉右開區間,upper_bound
a[m]=v 至少已經找到乙個,而右邊可能還有,因此區間變為[m,h)
a[m]>v 所求位置不可能在右邊,但有可能是m,因此區間變為[l,m]
a[m]設lower_bound和upper_bound的返回值分別為l和r,則v出現的子串行為[l,r)。這個結論當v不存在的時候也成立:此時l=r,區間為空。
這裡實現的就是stl中的同名函式。
三分支版本:
二分查詢詳解
兩分支版本:
問題描述:有乙個按非降序排列的有序陣列a[0...n-1]和乙個數v
1. 求陣列a中最後一次出現的數v的下標
為了更清楚地說明問題,下面討論一下當迴圈體內l和h之間(包含l和h)最後只剩3個和2個元素時的情況,初始元素個數超過3個的最後都會轉化為這兩種情況之一。
只剩3個元素時,可能出現2中情況,一種是其中裡面含有v,另一種是不含v。假設v = 2,那麼含有v的可能出現以下幾種情況:
//二分查詢演算法版本b:在有序向量的空間[l,h)內查詢元素v,0<=l<=h<=_size
int bisearch(int* a,int l,int h,int
v)//
出口時h=l+1,查詢區間僅含乙個元素a[l]
return (e==a[l])?l:-1;//
查詢成功時返回對應的秩,否則統一返回-1
}//有多個命中元素時,不能保證返回秩最大者;查詢失敗時,簡單返回-1,而不能指示失敗的位置
1int bisearch(int* a,int l,int h,intv)2
11return l--;
12 }
2020 09 02二分查詢那些坑
如下兩種實現方式,right 邊界的取值,直接影響著演算法的實現細節,這些細節稍不小心就會犯錯。二分查詢看似簡單,實則不然,真正能考慮到所有細節,把 寫準確是很不容易的。int binarysearch int nums,int target return 1 int binarysearch in...
迭代二分查詢二分查詢
在寫這篇文章之前,已經寫過了幾篇關於改迭代二分查詢主題的文章,想要了解的朋友可以去翻一下之前的文章 bentley在他的著作 writing correct programs 中寫道,90 的計算機專家不能在2小時內寫出完整確正的二分搜尋演算法。難怪有人說,二分查詢道理單簡,甚至小學生都能明確。不過...
leetcode 那些不像二分的二分
魯迅先生曾經說過 有的二分問題,看著不像二分,但是是真的二分,一旦二分,是真的666 2021年3月21日leetcode周賽第三題 寫這道題是為了記錄一下這個精妙的二分 貪心解法。class solution else return high 計算長度為len的陣列,並且最大值為high的最小總和...