1.介绍一下二分
- 什么是二分?
二分法,顾名思义,就是一次分成两份,实际也就是这样(其实并不是)
咳咳,二分法,就是在一个单调有序的序列(或者集合,函数,只要是单调有序的就行)中查找一个解,每次把当前的范围从中间劈开分为左右两部分,然后判断解在哪个部分中并且不断地调整上下界,直到找到答案。
二分是一种常用的算法,常常是我们解决问题的突破口(在你没有思路的时候暴力二分求解)。
二分的基本用途是在单调序列或者单调函数中进行查找操作。因此如果问题的答案具有单调性,就可以考虑二分判定
是的,二分和判定
如果你只二分而不判定的话,就无法继续二分,也无法退出二分,就相当于你卡在了一个非常尴尬的位置上
所以二分的时间复杂度为O(二分次数*单次判定的复杂度)
如果是在正整数上二分的话,二分次数就是log n,判定结束二分时只需要看看目前左右端点是否一样就行了
而如果是在实数上二分的话,就需要判定精度,abs(l-r)是否小于给定的精度
- 二分要注意的事项
1.单调性,单调性,单调性(重要的事情说三遍)
只有具有单调性的集合或者函数才可以用二分,否则就算你分出来了区间也不能进行下一步的操作。如果当前给定的数据不具有单调性,你不妨给他排一下序
2.虽然你使用了二分,而且单纯的二分复杂度也不是很高,但你还是要好好写一写检查的函数,否则还是会TLE
2.二分的常见模型
1.二分答案
看到最小值最大或者是最大值最小的问题,基本上就是二分没跑了,需要在确定答案后,配合其他算法检查这个答案是否合理
2.二分查找
用具有单调性的布尔表达式求解分界点
3.代替三分
有的时候对于一些单峰函数,我们可以用二分导函数的方法求解函数极值(什么是导函数?详情参见百度百科或高中选修2-3或高等数学(一)
3.二分板子
1.整数定义域上的二分
代码:
bool check(int l) { //...... } int erfen(int 1,int n) { int l=1,r=n; int ans; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid; } return l; }
2.实数定义域上的二分
代码:
double eps=0.001;//这个随着题目要求而改变 bool check(double l) { //...... } double erfen(double 1,double n) { double l=1,r=n; double ans; while(fabs(l-r)>eps) { double mid=(l+r)/2.0; if(check(mid)) r=mid; else l=mid; } return l; }
(在你没有思路的时候暴力二分求解)