二分查詢,以及類似問題

2021-10-03 08:17:28 字數 4298 閱讀 2299

關鍵點:二分查詢的最終步驟會經歷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]的位置上).

為什麼呢?因為元素沒有找到時,最後乙個查詢的區間大小肯定是1,也就是必然存在p=r的過程,如果a[p]>e,應當返回p;如果a[p]關鍵點:明確陣列每一次比較的中間元素

如果陣列有奇數個元素,則中間元素是唯一的;如果陣列有偶數個元素,則中間元素是偏左側的那個。

如果中間元素仍然不匹配,此時需要選擇左側或者右側的區間,注意,中間元素不再包含在內。因此,如果初始有14個元素,則先比較第7個元素,如果小於該元素,則第二次往左側比較,有6個元素而不是7個元素,中間元素是第3個元素。

題目:二分查詢的最多比較次數是多少次?

假定有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 二分查詢的前提...