二分是一种思想,二分查找是二分思想的一个应用
有单调性的题目一定可以二分,可以二分的题目不一定非得有单调性。二分的本质并不是单调性。
不需要考虑mid+1、mid-1的二分查找模板,希望大家都能学会
整数二分
二分可以分出来两个点:
这两个点分别是:
满足红色性质的最后一个点,即check性质的最右边的点
满足绿色性质的第一个点,即check性质的最左边的点
如果你要找的这个点是你check()函数满足的最后一个点,那么用模板一去找到这个点
如果你要找的这个点是你check()函数满足的第一个点,那么用模板二去找到这个点
例如:数的范围中找到x在序列中的第一个位置和最后一个位置。
那么第一个位置就是要找满足check函数的第一个数,就要用模板二
最后一个位置就是要找满足check函数的最后一个数,就要用模板一
#include <iostream>
using namespace std;
const int N =1e5 + 10;
int n, m;
int q[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0 ;i < n; i ++ ) scanf("%d", &q[i]);
while (m--)
{
int x;
scanf("%d", &x);
// 模板2 希望找到的值在check性质的最左边
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r >> 1;// 如果是l = mid,不需要那么一定要+1, 因为c++ 除法向下取整,如果l = r-1时,mid=l+r/2=l,r=mid=l有意义,会不满足l<r跳出循环
if (q[mid] >= x) r = mid;
else l = mid + 1;// 如果上面是r = mid,下面直接l = mid + 1:
}
if (q[l] != x) cout << "-1 -1 " << endl;
else
{
cout << l << ' ';
// 模板1 希望找到的值在check性质的最右边
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;//如果是l = mid,那么一定要+1, 因为c++ 除法向下取整,如果l = r-1时,mid=l+r/2=l,l=mid=l没有意义,会一直满足l<r死循环
if(q[mid] <= x) l = mid;
else r = mid - 1;// 如果上面是l = mid,下面直接r = mid - 1:
}
l
cout << l << endl;
}
}
return 0;
}
浮点数二分
如果check mid >=满足
那么说明目标在左边 更新 r=mid
否则说明目标在右边,更新l=mid
#include <iostream>
using namespace std;
int main()
{
double x;
cin >> x;
double l = -100, r= 100;
//浮点数二分模板,浮点数可以整除,只要考虑范围就行,不用+1 -1
while (r - l > 1e-8)//经验在要求的精度上加2即可
{
double mid = (l + r) / 2;
if(mid*mid*mid >= x ) r = mid;
else l = mid;
}
printf("%.6lf\n", l);
return 0;
}