二分查詢演算法思想很簡單,但是處理好邊界要細心。
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...