前言
只是记录
这道题是二分查找
什么是二分查找?
简述:查找的时候把序列一分为二,每次都把要找的数 (a) 和序列中间那个数 (b) 比,如果a>b,就从 b 的后面开始找;如果a<b,就从b的前面开始找(找的时候也是从这样一分为二,跟中间的数比较)。为什么可以找呢?因为二分查找必须是在有序的数组里找。有序性就决定了,如果a>b,那么b前面的数都<a,要找的数在b后面;a<b同理。
题目
模板
整数二分查找
/*检查x是否满足某种性质*/
bool check(int x){/*...*/}
/*[l,r] => [l,mid],[mid+1,r]*/
int Search_L(int l,int r)
{//查找左边界(边界最左边那个数)
while(l<r)
{
int mid=l+r>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
return l;
}
/*[l,r] => [l,mid-1],[mid,r]*/
int Search_R(int l,int r)
{//查找右边界(边界最右边那个数)
while(l<r)
{
int mid=l+r+1>>1;//需要+1,防止死循环
if(check(mid))
l=mid;
else
r=mid-1;
}
return l;
}
-
每次使用这两个模板的时候,先想是找这个区间的左端点还是右端点,然后选择使用模板,最后再去写判断条件。
思路
输入样例
1 2 2 3 3 4
假如,查找3,但是有重复的,因此需要划分左右边界 | 3 3 |,查找左边界的3,用Search_L模板,查找右边界的3,用Search_R模板。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N];
int n,q,k;
int SL(int l,int r,int k)
{
while(l<r)
{
int mid=l+r>>1;
if(a[mid]>=k)
r=mid;
else
l=mid+1;
}
return l;
}
int SR(int l,int r,int k)
{
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<=k)
l=mid;
else
r=mid-1;
}
return l;
}
int main()
{
cin>>n>>q;
for(int i=0;i<n;i++)
cin>>a[i];
while(q--)
{
cin>>k;
int l=SL(0,n-1,k);
int r=SR(0,n-1,k);
if(a[l]!=k)
cout<<-1<<" ";
else
cout<<l<<" ";
if(a[r]!=k)
cout<<-1<<endl;
else
cout<<r<<endl;
}
return 0;
}
题目链接
https://www.acwing.com/problem/content/791/
参考
https://cpt1024.blog.youkuaiyun.com/article/details/123905773