1.二分概念
二分算法,又称折半查找,即在一个单调有序的集合中查找一个解。每次分为左右两部分,判断解在哪个部分中并调整上下界,直到找到目标元素,每次二分后都将舍弃一半的查找空间。
2.算法复杂度:O(logn)
3.二分法常见模型
(1)二分查找
在一个单调有序的区间上求解分界点。
(2)二分答案
最小值最大(最大值最小)问题,这类双最值问题常常选用二分法求解,也就是确定答案后,配合贪心、DP等其他算法检验这个答案是否合理,将最优化问题转换为判定性问题。
注:一般题目默认在一个从小到大的区间上。
模板一:将区间划分为 [l,mid] 和 [mid+1,r]
int bsearch1(int l,int r) {
while(l < r) {
int mid = (l+r) / 2;
if( check(mid) ) r = mid;
else l = mid + 1;
}
return l;
}
注:
模板二:将区间划分为 [l,mid-1] 和 [mid,r]
int bsearch2(int l,int r) {
while(l<r) {
int mid = (l+r+1) / 2;
if( check(mid) ) l = mid;
else r = mid - 1;
}
return l;
}
模板三:将区间划分为 [l,mid-1] 和 [mid+1,r]
int bsearch(int l,int r) {
int ans = 0;
while(l <= r) {
int mid = (l+r) / 2;
if( check(mid) ) { ans = mid; l = mid - 1; }
else r = mid - 1;
}
return ans;
}
注:模板1和模板2配套使用,模板3可独立实现模板1和模板2,掌握1种即可。
类似数学对函数实行的二分法。
double bsearch(double l, double r) {
const double eps = 1e-6;
while (r - l > eps) {
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
注:
1.以数组为例(有序)
在从小到大的数组中,查找一个元素 k。
lower_bound(a+l,a+r,k) //二分查找第一个大于或等于k的数字
upper_bound(a+l,a+r,k) //二分查找第一个大于k的数字
查找范围:[I,r)。时间复杂度:O(logn)
对于lower_bound来说,当元素 k 存在时返回指向该元素的地址,如果k大于数组中任何一个值,则返回指向r的地址。如果k小于数组中任何一个值,则返回指向l的地址。
技巧:因为返回的是数组地址,所以可以减去数组来求得在数组中的位置。
int t = lower_bound(a+l,a+r,k) - a ;
此时若 t 属于 [l,r),则 a[t] >= k。
2.重载二分函数
重载为在从大到小的数组中,查找一个元素k,
或者在一个结构体数组中实行二分查找。
lower_bound(a+l,a+r,k,greater<int>() )
//二分查找第一个小于或等于k的数字
lower_bound(a+l,a+r,k,cmp)
//cmp 相当于重载 <
当元素k存在时返回指向该元素的地址,如果k大于数组中任何一个值,则返回指向l的地址。如果k小于数组中任何一个值,则返回指向r的地址。
3.其他容器
lower_bound(a.begin()+l,a.begin()+r,k) - a.begin();
//vector 可变长数组,deque 双端队列,其实和数组差不多
set<int>::iterator it = a.lower_bound(k) ;
//set ,集合,只能查找全体,返回的是迭代器,multiset和set差不多
除 vector 可变长数组,deque 双端队列,set 集合,multiset 外,其他容器很少用二分函数或者不能用二分函数。
4.lower_bound() 和 find() 的比较
find() 一般是 O(n) 的时间复杂度,但序列可以是无序的。
lower_bound() 一般是 O(logn) 的时间复杂度,但序列必须的有序的。
二者各有优劣,当数据量较大时尽量使用 lower_bound()。
二分答案一般求解最小值最大(最大值最小)问题,将求解答案二分,配合贪心、DP等其他算法检验这个答案是否合理,将最优化问题转换为判定性问题。一般整数问题整数二分,实数问题浮点数二分,本质是一样的。
复杂度一般为O(nlogn),适合解决再10^5范围内的数据。
注:参考内容
1.acwing ,y总
2.算法竞赛进阶指南,作者李煜东
3.《奥赛一本通》