整数二分法
不要纠结是左端点还是右端点的弄法,跟着题目走,比如题目说要你在上升序列中取小于t的最大的数,那就顺着写呗。a【mid】是不是要小于t,此时mid是不是在t左边且符合条件,那mid是不是就是l=mid,如果不满足是不是mid就在t的右边而且这个答案肯定不是mid,所以r=mid-1
1、确定一个区间,使得目标值一定在区间中
2、找一个性质,这个性质满足:
(1)这个性质具有二段性
(2)它可以让我们想要的答案成为二段性的分界点
第一类:ans是红色区间的右端点(对应图中ans在下面)
将【L,R】分成[L,M-1][M,R]
if M是红色的(在红色区域中),则答案必然在[M,R]之间的
else 说明ans在【L,M-1】
while(l<r){
m=(l+r+1)/2;
if m 红 : l=m;
else : r=m-1;
}
// 在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while (low < high)
{
int mid = (low + high + 1) / 2;
if (a[mid] <= x)//mid落在红色区域
low = mid;
else
high = mid - 1;
}
注意!!!
查找右端点时,我们相当于是求满足条件的最大数为多少,(<t的最大数)所以满足条件的一定是左端,并且左端取等,不满足条件的一定比右端右,所以减一
第二类:ans是蓝色区间的左端点(对应图中ans在上面)
将【L,R】分成[L,M-1][M,R]
if M是蓝色的(在蓝色区域中),则答案必然在【L,M】之间的
else 说明ans在【M+1,R】
while(l<r){
m=(l+r)/2;
if m在蓝色 : R=m;
else : L=m+1;
}
// 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (low < high)
{
int mid = (low + high) / 2;
if (a[mid] >= x)//mid落在蓝色区域
high = mid;
else
low = mid + 1;
}
不用考虑这么多,只要考虑是L=M还是R=M就行了
算法步骤:
1、找区间【L,R】,答案在其中
2、找一个判断条件,使得该判断条件具有二段性,并且答案一定是该二段性的分界点
3、分析终点M在该判断条件下是否成立。如果成立,考虑答案在哪个区间,如果不成立,考虑答案在哪个区间;
4、如果更新方式写的是R=MID,则不用做任何操作,如果更新方式是L=MID,则需要在计算MID的时候加上1
实数二分法
因为是落实到一个数所以不需要分两种情况
while (high - low > 1e-6)(1e-n,n根据题目对小数位数的精度要求再加2)
{
double mid = (low + high) / 2;
if (a[mid] >= x)//mid落在蓝色区域
high = mid;
else
low = mid;
}