二分查詢 lower bound

2021-10-14 07:09:09 字數 4712 閱讀 9347

二分查詢演算法思想很簡單,但是處理好邊界要細心。

3.尋找有序序列第乙個滿足某條件的元素的位置

4.lower_bound()和upper_bound()

(1)二分查詢的過程與序列的下標從0開始還是從1開始無關。

(2)若二分上界超過int型資料範圍的一半時,且欲查數在靠後位置時,mid=(left+right)/2的left+right可能會超過int導致溢位——可換為:mid=left+(right-left)/2防止溢位。

——附另一種二分查詢寫法:mid=min+((max-min)>>1),用位運算,三個》是無符號右移即邏輯右移,最高位補0。

#include

#include

//a為嚴格遞增序列,left為二分下界,right為二分上界,x為欲查詢的數

//二分區間為左閉右閉的[left,right],傳入的初值為[0,n-1]

intbinarysearch

(int a,

int left,

int right,

int x)

else

}return-1

;//查詢失敗,返回-1

}int

main()

;printf

("%d %d\n"

,binarysearch

(a,0

,n-1,6

),binarysearch

(a,0

,n-1,9

));system

("pause");

}

(1)求出序列中第乙個大於等於 x的元素的位置l;

#include

#include

//a為嚴格遞增序列,left為二分下界,right為二分上界,x為欲查詢的數

//二分區間為左閉右閉的[left,right],傳入的初值為[0,n]

intbinarysearch

(int a,

int left,

int right,

int x)

else

}return left;

//返回夾出來的位置

}int

main()

;printf

("%d %d\n"

,binarysearch

(a,0

,n-1,6

),binarysearch

(a,0

,n-1,9

));system

("pause");

}

輸出:3 6

(1)迴圈條件是leftright時[left,right]不再是閉區間,即作為元素不存在的判定原則,因此left≤right滿足時迴圈一直執行;

如果想要返回第乙個大於等於x的元素的位置,就不需要判斷x本身是否存在

——因為就算它不存在,返回的也是「假設它存在,它應該在的位置」,於是當left==right時,[left,right]剛好能夾出唯一的位置即所需的結果,因此只需要當left(2)由於當left == right時while迴圈停止,因此最後的返回值既可以是left,也可以是right。

(3)二分的初始區間應當能覆蓋到所有可能返回的結果。

二分下界顯然是0,但上界是n-1還是n:

考慮到欲查詢元素可能比序列中所有元素大,此時應當返回n(即假設它存在,它應該在的位置),因此二分上界是n,故二分的初始區間為[left,right]=[0,n]。

(2)求出第乙個大於x的元素的位置l。

#include

#include

//a為嚴格遞增序列,left為二分下界,right為二分上界,x為欲查詢的數

//二分區間為左閉右閉的[left,right],傳入的初值為[0,n]

intbinarysearch

(int a,

int left,

int right,

int x)

else

}return left;

//返回夾出來的位置

}int

main()

;printf

("%d %d\n"

,binarysearch

(a,0

,n-1,6

),binarysearch

(a,0

,n-1,9

));system

("pause");

}

按照(1)(2)x在序列中的存在區間就是左閉右開區間[l,r)。

栗子:若要查詢3則得到l=1,r=3;若要查詢4則得到l=r=4。

(1)和(2)都在解決乙個經典問題(大多數二分法問題都歸結於該問題):尋找有序序列中第乙個滿足某條件的元素的位置。

(1)即尋找第乙個滿足條件「值大於等於x」的元素的位置;(2)即尋找第乙個滿足條件「值大於x」的元素的位置。

//解決「尋找有序序列第乙個滿足某條件的元素的位置」問題的固定模板

//二分區間為左閉右閉的[left,right],初值必須能覆蓋解的所有取值。

intsolve

(int left,

int right)

else

}return left;

//返回夾出來的位置

}

(1)如果尋找最後乙個滿足「條件c」的元素的位置,則可以先求出【第乙個滿足「條件!c」的元素的位置】,然後該位置減1即可——最長回文子串的二分解法就用到了這點。

(2)若查詢序列中是否存在滿足某條件的元素,則使用最開始的二分查詢的寫法最合適。

標頭檔案為< algorithm>,兩者均用在乙個有序陣列或容器中。

lower_bound(first,last,val):尋找陣列或容器的[first,last)內的第乙個值大於等於val的元素的位置。

upper_bound(first,last,val):將上面的「大於等於」改為「大於」。

返回值:

陣列:返回該位置的指標;

容器:返回該位置的迭代器。

ps:若沒有想查詢的元素val,則兩者均返回可以插入該元素的位置的指標或者迭代器(即假設存在該元素,該元素應當在的位置)。

#include

#include

#include

using

namespace std;

intmain()

;//尋找-1

int* lowerpos=

lower_bound

(a,a+10,

-1);

int* upperpos=

upper_bound

(a,a+10,

-1);

printf

("%d, %d\n"

,lowerpos-a,upperpos-a)

;//尋找1

lowerpos=

lower_bound

(a,a+10,

1); upperpos=

upper_bound

(a,a+10,

1);printf

("%d, %d\n"

,lowerpos-a,upperpos-a)

;//尋找3

lowerpos=

lower_bound

(a,a+10,

3); upperpos=

upper_bound

(a,a+10,

3);printf

("%d, %d\n"

,lowerpos-a,upperpos-a)

;//尋找4

lowerpos=

lower_bound

(a,a+10,

4); upperpos=

upper_bound

(a,a+10,

4);printf

("%d, %d\n"

,lowerpos-a,upperpos-a)

;//尋找6

lowerpos=

lower_bound

(a,a+10,

6); upperpos=

upper_bound

(a,a+10,

6);printf

("%d, %d\n"

,lowerpos-a,upperpos-a)

;system

("pause");

}

輸出結果為:

0,0

0,13

,66,

610,10

如果想輸出欲查元素所在陣列/容器的下標,就不用臨時指標——直接令返回值減去陣列首位址。

#include

#include

#include

using

namespace std;

intmain()

;//尋找3

printf

("%d,%d\n"

,lower_bound

(a,a+10,

3)-a,upper_bound

(a,a+10,

3)-a);

system

("pause");

}

輸出結果為:3 6

二分函式lower bound

函式lower bound 在first和last中的前閉後開區間進行二分查詢,返回大於或等於val的第乙個元素位置。如果所有元素都小於val,則返回last的位置 舉例如下 乙個陣列number序列為 4,10,11,30,69,70,96,100.設要插入數字3,9,111.pos為要插入的位置...

H 指數 二分 lower bound二分

給定一位研究者 被引用次數的陣列 被引用次數是非負整數 編寫乙個方法,計算出研究者的 h 指數。h 指數的定義 h 代表 高引用次數 high citations 一名科研人員的 h 指數是指他 她 的 n 篇 中 總共有 h 篇 分別被引用了至少 h 次。其餘的 n h 篇 每篇被引用次數不超過h...

基礎演算法 二分 lower bound和upper

給乙個長度為n的a陣列和乙個長度為m的b陣列,問相鄰的b陣列元素中間最多有多少個a陣列元素?輸入第一行輸入t,代表t組樣例 輸入n和m,分別代表a陣列和b陣列的長度 輸入a陣列 輸入b陣列 輸出如果ans 0,輸出impossible 否則,輸出ans lower bound和upper bound...