二分
二分这个词大家应该不会陌生,他是一种思想,经常用来搜索或排序,二分思想就是说要把一串数字对半切开,前提是必须有序,然后比较中间数,不断的缩小范围。
一般的线性查询算法时间复杂度为O(n)
而二分的时间复杂度仅有O(logn)
二分的基本思路与实现
假设有一串数:1 4 7 8 10 13
我们要用二分来搜索10。
第一步:找到中间数:mid=(1+6)/2=3,第三个数为7,
第二步:我们发现10>7,所以要在7的右边查询,这时候左指针移到mid+1处,为4
第三步:更新mid值,mid=(l+r)/2=5
第四步:找到中间数,第五个数为10,程序结束
如果一直没有找到,直到 l >= r,那么意味着这个数串里没有这个数,
这个例子的复杂度只有O(3),如果是线性扫的话就要用O(5)了。
二分答案
二分答案的思想更加巧妙,就是通过不断缩小答案的范围从而找到答案,一般会有if语句判断;
二分样例代码
lef=1,righ=n;
while(lef<=righ){
mid=(int)((lef+righ)/2);
if(f>a[mid])
lef=mid+1;
else if(f<a[mid])
righ=mid-1;
else {
cout<<mid;
return 0;
}
}
二分相关函数
函数名 | 作用 |
---|---|
lower_bound (begin,end,n) | 在begin-end范围内查找第一个大于或等于n的数的位置 |
upper_bound (begin,end,n) | 在begin-end范围内查找第一个大于n的数的位置 |
binary_search(begin,end,n) | 判断n是否在begin-end范围内 |
例题:
P. 二分查找
内存限制:64 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
在一个单调递增的序列里查找X。
如果找到x,则返回x在数组中的位置
如果没有找到,则返回-1
输入格式
第1行:1个整数N(1<=N<=2000000), 表示元素的个数
第2行开始的若干行,每行10个空格分开的整数,总共N个整数,即为数组元素。
最后1行,1个整数X,表示要查找的元素
序列的位置从1开始编号。
输出格式
第1行:一个整数,表示x在序列中的位置。如果没有找到,则返回-1
样例
样例输入
5
1 3 5 7 9
7
样例输出
4
分析
这道题是一个非常典型的二分问题,思路如上。
代码
#include<bits/stdc++.h>
using namespace std;
int n,i,f,a[2000005],lef,righ,mid;
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
cin>>f;
lef=1;
righ=n;
while(lef<=righ){
mid=(int)((lef+righ)/2);
if(f>a[mid])
lef=mid+1;
else if(f<a[mid])
righ=mid-1;
else {
cout<<mid;
return 0;
}
}
cout<<-1;
}
E. 二分法求函数的零点
内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
有函数:
。
已知 , 且方程 在区间 有且只有一个根,请用二分法求出该根。
输入格式
无。
输出格式
该方程在区间 中的根。要求四舍五入到小数点后4位。
分析
这道题运用二分答案的思想来完成,不断在范围内取mid值,然后移动left或right值,不断缩小范围,从而找到我们要找的答案
代码实现
首先写一个关于这个方程的函数
double f(double x){
return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x *x+274*x-121;
}
本题给出了范围,可以直接用
double l=1.5,r=2.4,mid;
给出二分答案的核心代码
while(r-l>1e-7){
mid=(l+r)/2;//取mid值
if(abs(f(mid))<0.000005){//这道题有精度,要把0写多一点
printf("%.6lf",mid);
break;//直接break就行了
}
else if(f(mid)>0) l=mid;//随中间值的情况更改范围
else r=mid;
}
完整代码:
#include<bits/stdc++.h>
using namespace std;
double l=1.5,r=2.4,mid;
double f(double x){
return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x *x+274*x-121;
}
int main(){
while(r-l>1e-7){
mid=(l+r)/2;
if(abs(f(mid))<0.000005){
printf("%.6lf",mid);
break;
}
else if(f(mid)>0) l=mid;
else r=mid;
}
}