算法 基础算法 二分算法


二分算法

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;
} 

注:

  • mid = (l+r) / 2 可写成: mid = (l+r) >> 2 。
  • 对于很大的数据,l+r 可能会溢出,可写成 l+(r-1>>1) 。

模板二:将区间划分为 [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;
}

注:

  • 浮点二分也可以直接指定划分次数,而不需要指定精度。
  • 简单题一般会考函数的二分,难题一般放在二分答案里出。

三、STL 二分函数

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.《奥赛一本通》

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值