您的位置:首页 > 编程语言 > Go语言

SSL-1135 二分查找【二分,STL_algorithm,hash】

2018-03-29 21:11 393 查看
目录

大意
数据范围

二分思路
代码

algorithm思路
代码1

代码2

HASH思路
代码

大意

有一个按从小到大顺序组成的长度为nn的序列,现给出一个数,查询此数是否在这个序列中。若在,输出它的序号,若不再输出No Found.No Found.

数据范围

n<=10000,−231<=a[i]<=231n<=10000,−231<=a[i]<=231

二分思路

比较裸了,就是一个二分模板。

时间复杂度O(log(n))O(log(n))

代码

#include<cstdio>
using namespace std;int l,r,mid,a[10000],Q;
int main()
{
scanf("%d",&r);//序列的右边界
for(int i=0;i<r;i++) scanf("%d",&a[i]);//输入序列
scanf("%d",&Q);//查询的数
while(l<=r)
{
mid=(l+r)>>1;//二分
if(a[mid]==Q) return printf("%d",mid+1);//已经找到就直接输出,因为这个序列是从第0位开始的,所以要+1
if(a[mid]<Q) l=mid+1;else r=mid-1;//继续查找
}
puts("No Found.");//找不到
}


algorithm思路

利用C++中STL的algorithmalgorithm(算法)库中自带的两个函数

lower_boundlower_bound

upper_boundupper_bound

lower_bound(left,right,x)lower_bound(left,right,x)是在一个序列的leftleft到rightright范围间,小于x的最大元素的位置。

upper_bound(left,right,x)upper_bound(left,right,x)是在一个序列的leftleft到rightright范围间,小于等于x的最大元素的位置。

以上这两种函数时间复杂度均为O(log(right−left))O(log(right−left)),相当于二分查找的时间复杂度

注:leftleft和rightright均为地址

代码1

#include<cstdio>
#include<algorithm>
using namespace std;int a[10000],ans,n,Q;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&Q);//输入
ans=lower_bound(a,a+n,Q)-a;//因为找到的是它的地址,所以还要减a
if(a[ans]!=Q) puts("No Found.");else printf("%d",ans+1);//因为是找到第一个小于的,所以要加一。
}


代码2

#include<cstdio>
#include<algorithm>
using namespace std;int a[10000],ans,n,Q;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&Q);//输入
ans=upper_bound(a,a+n,Q)-a;//这个就可以直接找到等于的了
if(a[ans-1]!=Q) puts("No Found.");else printf("%d",ans);//因为是从第0位开始,所以要减1
}


HASH思路

对于判断一个数是否在一个集合内,最快的方法是开一个桶,使得

h[key]=keyh[key]=key

但由于此题数据较大,不可能开一个这么大的桶,因此,一般情况下有两种解决方案。

1.快速排序+二分查找,时间复杂度O(nlogn+logn)O(nlogn+logn)

2.HASH存储,时间复杂度O(1)O(1)(忽略冲突)

因为这题是已经排好序的,所以第一种算法和第二种算法相差无几,但若数据再大点肯定是HASH更优。当然,这个再大是有限度的,当数据大到一定程度,使HASH表冲突超多,那么快速排序+二分查找还是最保险的

因为这题只有10000个数,所以直接用一个质数HASH就行了,再用一个结构体保存位置,就可以AC了。

代码

#include<cstdio>
#define p 100003
#define hash(a) a%p//hash函数
using namespace std;
int n,x,Q,i;
int abs(int x){return x<0?-x:x;}//因为有可能是负数,所以要用到abs
struct HASH
{
int num,Onum;//num是这个位置对应的数字,Onum是序号
}h[p];
int find(int x)//查找x的位置
{
int y=hash(abs(x));
while(h[y].num&&h[y].num!=x) y=hash(++y);
return y;
}
void push(int x,int y)//放入hash表并存储序号
{
int z=find(x);//查找
h[z].num=x;
h[z].Onum=y;//存储
}
bool init(int x)
{
return h[find(x)].num==x;//判断
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&x),push(x,i);//输入+放入
scanf("%d",&Q);
if(init(Q)) printf("%d",h[find(Q)].Onum);else puts("No Found.");//直接判断,输出
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: