二分查找也称折半查找,顾名思义,就是每次查找去掉不符合条件的一半区间,直到找到答案(整数二分)或者和答案十分接近(浮点二分)。
整数二分
具有单调性不一定能用二分,不具有单调性一定不能二分。
二分就是在一组数中找到符合某个条件的数的位置。
二分套这两个模板,肯定没错!(只要判断条件写对)亲测有效!!!
如果题目明确说了 要求最小值(最前面的值)还是求最大值(最后面的值),就能判断是用模板2(求最小),还是用模板1(求最大)。
之后再根据模板1,或模板2,写出对应的判断条件;
例题AcWing789数的范围:789. 数的范围 - AcWing题库
题面:
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=998244353;
ll n,q;
ll a[N];
signed main()
{
scanf("%lld %lld",&n,&q);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
while(q--)
{
ll x;
scanf("%lld",&x);
int l=0,r=n-1;
//在右边
while(l<r)
{
int mid=l+r>>1;
if(a[mid]>=x) r=mid;
else l=mid+1;
}
if(a[l]!=x) cout<<"-1 -1"<<endl;
else
{
cout<<l<<' ';
int l=0,r=n-1;
while(l<r)
{
//在左边
int mid=l+r+1>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}
浮点二分
例题:找一个浮点数的算术平方根。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
double x;
cin>>x;
double l=-10000,r=10000;
while(r-l>1e-8)//范围很小时结束,一般这个范围比给的数的范围小100倍才精确。这里还可以直接循环100次
{
double mid=(l+r)/2;
if(mid*mid>=x) r=mid;
else l=mid;
}
cout<<l<<endl;
return 0;
}
STL中的二分函数(lower_bound(),upper_bound())
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。
通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。
通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。