ฅ(๑˙o˙๑)ฅ 大家好, 欢迎大家光临我的博客:面向阿尼亚学习
算法学习笔记系列持续更新中~
一、前言
二分,是一种求极值的算法,通常已知答案的取值范围,然后每次取
取值范围的中点
,判断之是否可行,然后找可行的一半处理。
二、二分算法的介绍
二分查找的最优时间复杂度为O(1) 。
二分查找的平均时间复杂度和最坏时间复杂度均为 O(logn)。因为在二分搜索过程中,算法每次都把查询的区间减半,所以对于一个长度为n 的数组,至多会进行 O(logn) 次查找。
三、二分算法的运用
前提
:使用二分算法,数组一定要是有序的(单调的),不能是乱序!
因为
:二分算法就是我们知道当前的候选区间中,一定存在我们要找到的答案,而且我们发现这个区间拥有单调性质此类的性质,那么我们可以不停地缩减候选区间的范围,达到排除无用答案的效果.
二分查找的主要步骤
当想找不满足性质的边界值
1.找中间值 mid = (l+r+1)/2
2.if(check(mid))等于true或者是false
3.check(m)是检查m是在不满足性质的区间
4.更新l或者r
当想找满足性质的边界值
1. 找中间值 mid = (l+r)/2
2. if(check(mid))等于true或者是false
check(m)是检查m是在满足性质的区间
3. 更新l或者r
归结上面的两种二分方法,步骤为:
先写一个check函数
判定在check的情况下(true和false的情况下),如何更新区间。
在check(m)==true的分支下是:
l=mid的情况,中间点的更新方式是m=(l+r+1)/2
r=mid的情况,中间点的更新方式是m=(l+r)/2
这种方法保证了:
1. 最后的l==r
2. 搜索到达的答案是闭区间的,即a[l]是满足check()条件的。
1. 整数二分模板
如下:
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
2.浮点数二分模板
浮点数二分的本质也是边界, 唯一区别是浮点数没有整除, 区间长度可以严格的缩小一半
当区间长度足够小时, 便可以认为是一个数
如下:
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求, 一般比所求精度高 2
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
最后
莫言真理无穷尽,寸进自有寸进欢