二分包括二分查找和二分答案
二分查找
二分查找分为整数二分和浮点数二分。其实二分和单调性关系不是绝对的,但是二分是永远基于单调性的,可以总结为有单调性的一定可以二分,而能二分的不一定具有单调性,点击这里参考这道题,
LeetCode
里面有很多非单调用二分查找的
整数二分—需要考虑边界
整数二分需要考虑边界问题,大佬yxc总结的两个万能模板,永远不会错
,如下
模板一:如果更新方式是 l = m i d + 1 , r = m i d l=mid+1,r=mid l=mid+1,r=mid,即答案尽量往左边找,那么 m i d mid mid的更新方式是 m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2,向下取整,模板如下
int binary_find(int l, int r)
{
while(l < r)
{
int mid = (l + r) >> 1;//向下取整
if(check(mid))//check函数根据题目来写
l = mid + 1;
else
r = mid;
}
return l;
}
模板二:如果更新方式是 l = m i d , r = m i d − 1 l=mid,r=mid-1 l=mid,r=mid−1,即答案尽量往右边找,那么 m i d mid mid的更新方式是 m i d = ( l + r + 1 ) / 2 mid=(l+r+1)/2 mid=(l+r+1)/2,向上取整,模板如下
int binary_find(int l, int r)
{
while(l < r)
{
int mid = (l + r + 1) >> 1;//向上取整
if(check(mid))//check函数根据题目来写
l = mid;
else
r = mid - 1;
}
return l;
}
但不管是哪种更新方式,循环条件都是while(l<r),这样能保证退出循环的时候一定有l=r
为什么更新方式是
l
=
m
i
d
,
r
=
m
i
d
−
1
l=mid,r=mid-1
l=mid,r=mid−1,
m
i
d
mid
mid的更新方式是
m
i
d
=
(
l
+
r
+
1
)
/
2
mid=(l+r+1)/2
mid=(l+r+1)/2呢?
举个简单的栗子,当你在
[
0
,
1
]
[0,1]
[0,1]这个区间查找1这个元素,最开始
l
=
0
,
r
=
1
l=0,r=1
l=0,r=1,如果你用
m
i
d
=
(
l
+
r
)
/
2
mid=(l+r)/2
mid=(l+r)/2,那么
l
l
l永远是0,
r
r
r永远是1,而
m
i
d
mid
mid也永远是0,查找不到1,陷入了死循环。这样处理就是为了避免死循环
模板题链接:AcWing 789.数的范围
浮点数二分—不需要考虑边界
浮点数二分就没有整数二分那么多的边界问题了,更新方式都是
l
=
m
i
d
,
r
=
m
i
d
,
m
i
d
=
(
l
+
r
)
/
2
l=mid,r=mid,mid=(l+r)/2
l=mid,r=mid,mid=(l+r)/2,需要特别注意的是,更新方式里面l和r都不能加1
。
根据yxc大佬的经验之谈,如果题目叫你保留
n
n
n位小数,一般要把精度
e
p
s
eps
eps设置成
1
e
−
(
n
+
2
)
1e-(n+2)
1e−(n+2),也就是比要保留的小数位数多两位
,比如说叫你保留四位小数,精度可以设置成
1
e
−
6
1e-6
1e−6,以此类推,模板如下:
double binary_find(double l, double r)
{
double eps = 1e-6;//一般比要求的精度多两位
while(l + eps < r)
{
double mid = (l + r) / 2;
if(check(mid))
l = mid;
else
r = mid;
}
return l;
}
模板题链接:AcWing 790.数的三次方根
二分答案
二分答案的题目一般是答案在一个区间内,而且答案在这个区间内单调(说起来有点抽象,题做多了就能理解了hh),然后我们就可以借助二分来不断缩小这个区间来查找这个答案
这种题目一般有一个特征,就是叫你求
1、最小的最大值
,求最小的xx值就是尽量把答案往左边靠,就是对应上面的模板一
2、最大的最小值
,求最大的xx值就是尽量把答案往右边靠,就是对应上面的模板二
话不多说,上模板题:洛谷P2678 跳石头
这道题的答案在一个固定的区间内,也就是
[
1
,
1000000000
]
[1,1000000000]
[1,1000000000]内,而且我们二分答案的时候,答案一定是单调的,因为如果对于一个距离
x
x
x,我们要移动的石头数目大于
M
M
M,所以对于所有大于
x
x
x的值,我们需要移动的时候数目肯定比
x
x
x对应的多,所以答案一定在小于
x
x
x的区间内,所以答案单调。而且这道题要我们求最短跳跃距离的最大值,即最大的最小值(最短跳跃距离),对应模板二,写就完事了
另外几道例题:
1、洛谷 P1824 进击的奶牛
2、AcWing 102.最佳牛围栏
3、Max Median
4、Increasing by Modulo
最后两道可有点难度哟