二分
整数二分:有单调性的一定可以二分。
二分的本质:某个性质可以将区间一分为二,划分图示:
圈一寻找的是第一个箭头,即红色线段的右端点。
圈二寻找的是第二个箭头,即绿色线段的左端点。
问题1、如何选择用哪一个模板:
先写mid,在写函数check时,考虑更新的区间,即寻找的到底是左端点还是右端点。
问题2、为什么加一
为了防止死循环。
应用
给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。
如果数组中不存在该元素,则返回“-1 -1”。
#include<iostream>
using namespace std;
const int N=1e5+10;
int q[N],n,m;
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);
int l=0,r=n-1;
while(l<r){
int mid= (l + r )>> 1;
if(q[mid]>=x) r=mid;
else l=mid+1;
}
if(q[l]!=x) printf("-1 -1\n");
else{
cout<<l<<' ';
int l=0,r=n-1;
while(l<r){
int mid=( l + r +1 )>> 1;
if(q[mid]<=x) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
}
return 0;
}
总结
先确定边界,根据图形确定求解哪一个边界,要是ture的话答案在哪个区间里。
在一个区间内部确定答案,二分,选择答案所在的区间。当区间长度为1时则是答案。
即,根据问题分析出答案的性质,进行二分,看答案会在哪个区间,每次进行二分的时候都要确保答案在区间里。
浮点数的二分
浮点数的二分不需要考虑边界问题。
#include<iostream>
using namespace std;
int main(){
double x;
cin>>x;
double l=0,r=x;
while(r-l>1e-6)
{
double mid=(l+r)/2;
if(mid*mid>x) r=mid;
else l=mid;
}
print("%d",l);
return 0;
}
高精度
笔试中偶尔出现,面试中不常考