關鍵點:二分查詢的最終步驟會經歷2個元素,1個元素,0個元素的階段,利用這幾個階段確定最終的下標。
題目:在乙個有序陣列中查詢某個元素的比較序列
偽**:
binary-search(a,e)
: p=
0,r=a.length-
1while p<=r:
m =(p+r)/2
if a[m]
> e:
r = m -
1else
if a[m]
< e:
p = m +
1else
return m
return
-p
如果查詢失敗,該查詢返回的下標,可以證明a[r]e成立
關鍵點:如果未找到元素,返回左指標的負值提供插入位置。
當找到元素時,該函式返回其中乙個下標;如果沒有找到,則返回插入點的位置(即將e插入到a[r]的位置上).如果中間元素仍然不匹配,此時需要選擇左側或者右側的區間,注意,中間元素不再包含在內。因此,如果初始有14個元素,則先比較第7個元素,如果小於該元素,則第二次往左側比較,有6個元素而不是7個元素,中間元素是第3個元素。為什麼呢?因為元素沒有找到時,最後乙個查詢的區間大小肯定是1,也就是必然存在p=r的過程,如果a[p]>e,應當返回p;如果a[p]關鍵點:明確陣列每一次比較的中間元素
如果陣列有奇數個元素,則中間元素是唯一的;如果陣列有偶數個元素,則中間元素是偏左側的那個。
題目:二分查詢的最多比較次數是多少次?
假定有2^k個元素,則每次比較最多仍然剩餘 2^(k-1)個元素,k=0時需要比較1次,所以最多需要k+1次。
題目:在某個序列中,二分查詢的平均查詢次數?
解:將陣列構造成平衡二叉樹,第一層的元素需要查詢1次,第二層的元素需要查詢2次,然後統計所有元素的查詢次數,除以元素個數即可
題目:返回最左插入位置和最右插入位置
解:以最左插入位置為例。考察插入點i的性質,如果i>0,則顯然有a[i-1]=e,這是目標插入點的性質。
關鍵點:分治法子問題,基本問題是空陣列只有乙個插入點。考慮基本問題,可以在o(1)複雜度內完成即為基本問題。
迴圈不變式:在縮放過程中,我們考慮 [p,r)區間內的元素性質,如果[p,r)內的元素都小於e,則顯然插入點在區間右側。如果[p,r)的元素都大於等於e,則插入點在區間左側或左邊界。
在迴圈過程中,我們比較中點元素a[m]與e的大小,如果a[m]>=e,則插入點在[r,m)中,重複該查詢過程即可;如果a[m]所以實際上是分治法。
binary-search-leftmost(a,e)
: p=
0,r=a.length
while pm =
(p+r)/2
if a[m]
>= e:
r = m
else
: p = m +
1return p
最後的判斷,如果陣列元素大於1個,一定滿足a[p]>=e;因此它僅針對陣列元素等於1和0的情況.
查詢過程中,a[m]可以構成所有的候選佇列,如果我們需要的是偏右側的位置,則令m=(p+r+1)/2;如果是偏左側的位置,則m=(p+r)/2.
因為考察比較元素的序列,我們期望當區間有偶數個元素時,總是判斷較左或較右的位置,這樣,當區間終止到只有乙個元素時,該元素一定是最左或最右的。
二分問題可以按照待查詢目標元素進行區分:
1.大於e的最小值
2.大於等於e的最小值
3.小於e的最大值
4.小於等於e的最大值
5.等於e的最小值(下標最小)
6.等於e的最大值(下標最大)
其中問題5其實等價於問題2並判斷最終元素是否等於e,問題6等價於4並判斷最終元素是否等於e。
我們可以知道,目標元素將陣列分成兩個部分,一部分是滿足判斷條件的所有元素,另一部分是滿足相反條件的所有元素。假定條件為f,則每次取區間中點判斷該元素是否滿足條件f,如果滿足,則中點的一側的所有元素都將滿足這個條件(只考慮大於,大於等於,小於,小於等於,也就是不包含問題5,6)。排除其中滿足條件f的元素,也就是中點一側的元素,但是中點仍將包含在內。
如果中點不滿足條件,則滿足條件的元素在其中一側,排除中點即可。
r的取值,因為每次需要排除滿足條件的區間,因此要保證滿足條件的區間元素數量至少是1。如果是排除左側區間,則r=(i+j+1)/2, 保證 i通用二分查詢偽**:
確定條件f, 如果f(a[i]) == true則f(a[i+1]) == true, 則滿足條件的元素在中點右側,否則在中點左側。
while i以查詢某個元素e的最右插入位置為例,顯然該位置是小於等於e的最大值的下標加上1,查詢過程如下:
條件f = a[i]<=e,如果陣列遞增,則滿足條件的元素在左側;否則在右側。
while i同理,查詢某個元素e的最小插入位置,則顯然該位置就是大於等於e的元素中的最小值。
插入位置有[0,n]個可選值,因此初始化指標應當是r=0,p=n,由於插入位置一定存在,因此只需要將區間的大小縮小到1即可。區間的目標元素滿足e>=target.
class
solution
return p;
}}
題目:34. find first and last position of element in sorted array
在乙個排序的陣列中,找到指定元素的區間解: 找到該元素的最左側相鄰元素位置r0(argmax(etarget)),則最終的區間就是[r0+1,r1-1].
class
solution
// [r1,p1] rightmost insert position (argmax(e>target))
int r1=
0,p1=nums.length;
while
(r1if(r0+
1>r1-1)
return
newint
;return
newint
;}}
包含元素的範圍主要取決於argmax或者argmin, m的位置則取決於區間應當偏左還是偏右,偏左的區間,右側可能沒有值,所以偏左。
1.不要使用二分查詢實現方向不一致的搜尋,比如在遞增陣列中,查詢小於等於某個元素的最大值,如果最大值有多個,返回最左側的乙個。
這個問題使用二分查詢無法實現,因為區間排除的方向有矛盾。
題目:4. median of two sorted arrays(hard)
給定兩個排序的陣列nums1和nums2,查詢兩個陣列的中位數.要求時間複雜度: o(log(n+m))解:leetcode-xhd2015-4. median of two sorted arrays
首先在第乙個陣列上進行二分查詢,每次查詢,判斷這個數的狀態是否能夠滿足二分條件,即小於等於它的元素數量應當是size/2+1.
如果第乙個陣列沒有查詢到,則反轉過來查詢即可。
class
solution
return
(least+most)
/2.0;}
/** * do binary search on nums1
* and determine whether there exists required elements satisfying the condition
*/boolean
findmedium
(int
nums1,
int[
] nums2)
return
true;}
}return
false;}
}
1201. ugly number iii(medium) 順序查詢以及二分查詢
include include define list init size 100 define listincrement 10 define ok 1 define error 0 define overflow 2 define eq a,b a b define lt a,b a b def...
列表查詢以及二分查詢
一 列表查詢 1 列表查詢 從列表中查詢指定元素 2 順序查詢 從列表第乙個元素開始,順序進行搜尋,直到找到為止。返回找到的那個索引 3 二分查詢 從有序列表的候選區data 0 n 開始,通過對待查詢的值與候選區中間值的比較,可以使候選區減少一半。二分查詢 時間複雜度是o logn 二分查詢的前提...
列表查詢以及二分查詢
一 列表查詢 1 列表查詢 從列表中查詢指定元素 2 順序查詢 從列表第乙個元素開始,順序進行搜尋,直到找到為止。返回找到的那個索引 3 二分查詢 從有序列表的候選區data 0 n 開始,通過對待查詢的值與候選區中間值的比較,可以使候選區減少一半。二分查詢 時間複雜度是o logn 二分查詢的前提...