当在找一个边界的时候,我们要保证这个边界把左右两部分分成两个不同性质的部分,比如如果要在一个数组中查找一个数的话,我们目的是查找这个数,实际上是查找他的边界,所以我们需要先把这个数组排序,排序之后这个数的左边都小于等于他,右边都大于等于他,然后我们就可以利用性质来找边界,先定义左边界l和右边界r,然后while(l<r)的时候找中间值mid=(l+r)/2,然后根据具体实例进行lr边界的变化,核心代码是:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,x;
int a[100005];
for(int i=0;i<n;i++)cin>>a[i];//输入a数组的数
sort(a,a+n);//千万记得排序
cin>>x;
int l=0,r=n-1;//左右边界是左右下标
while(l<r){
int mid=(l+r)/2;
if(a[mid]>=x)r=mid;//因为最后包含x这个边界,所以判断条件是>=x
else l=mid+1;
}
if(a[l]==x){//当找到边界时等于就有不等于就没有
printf("YES\n");
}else printf("NO\n");
例题:
蒜头君手上有个长度为 nn 的数组 AA。由于数组实在太大了,所以蒜头君也不知道数组里面有什么数字,所以蒜头君会经常询问整数 xx 是否在数组 AA 中。
输入格式
第一行输入两个整数 nn 和 mm,分别表示数组的长度和查询的次数。
接下来一行有 nn 个整数 a_iai。
接下来 mm 行,每行有 11 个整数 xx,表示蒜头君询问的整数。
输出格式
对于每次查询,如果可以找到,输出"YES"
,否则输出"NO"
。
数据范围
1 \le n, m \le 10^5, 0 \le x \le 10^61≤n,m≤105,0≤x≤106。
Sample 1
Inputcopy | Outputcopy |
---|---|
10 5 1 1 1 2 3 5 5 7 8 9 0 1 4 9 10 | NO YES NO YES :NO |
答案:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int a[100005];
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)cin>>a[i];
sort(a,a+n);
while(m--){
int x;
cin>>x;
int l=0,r=n-1;
while(l<r){
int mid=(l+r)/2;
if(a[mid]>=x)r=mid;
else l=mid+1;
}
if(a[l]==x){
printf("YES\n");
}else printf("NO\n");
}
return 0;
}
当找的数是浮点数的时候,我们这时的l,r,mid都应该是double类型,所以就不能用while(l<r)这个条件了,因为算出来的mid是小数点,所以我们需要规定如果r-l<1e-6那么我们就可以认为他们非常近了,就可以输出了,所以把条件改为while(r-l>1e-6),代码如下:
while(r-l>=1e-6){
double mid=(l+r)/2;
if(mid>=x){
r=mid;
}else l=mid;
}