目录
一、840 模拟散列表
维护一个集合,支持如下几种操作:
I x
,插入一个数 x;Q x
,询问数 x 是否在集合中出现过;现在要进行 N 次操作,对于每个询问操作输出对应的结果。
输入格式
第一行包含整数 N,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为
I x
,Q x
中的一种。输出格式
对于每个询问指令
Q x
,输出一个询问结果,如果 xx 在集合中出现过,则输出Yes
,否则输出No
。每个结果占一行。
数据范围
1≤N≤105
−109≤x≤109输入样例:
5 I 1 I 2 I 3 Q 2 Q 5
输出样例:
Yes No
1、拉链法
#include <iostream>
#include <string.h>
using namespace std;
const int N=1e5+3;
int a[N],e[N],ne[N],idx;
void insert(int x)
{
int k=(x%N+N)%N;
e[idx]=x,ne[idx]=a[k],a[k]=idx++;
}
bool que(int x)
{
int k=(x%N+N)%N;
for(int i=a[k];i!=-1;i=ne[i])
if(e[i]==x) return 1;
return 0;
}
int main()
{
int t;
cin>>t;
memset(a,-1,sizeof a);
while(t--)
{
string op;
int x;
cin>>op>>x;
if(op[0]=='I') insert(x);
else
{
if(que(x)) puts("Yes");
else puts("No");
}
}
}
2、开放寻址法
#include <iostream>
#include <string.h>
using namespace std;
const int N=2e5+3,null=0x3f3f3f3f;
int a[N];
int find(int x) //如果x在哈希表中返回其下标 如果x不在哈希表中 k是x要存储的下标
{
int k=(x%N+N)%N;
while(a[k]!=null&&a[k]!=x)
{
k++;
if(k==N) k=0;
}
return k;
}
int main()
{
int t;
cin>>t;
memset(a,null,sizeof a);
while(t--)
{
string op;
int x;
cin>>op>>x;
int k=find(x);
if(op[0]=='I') a[k]=x;
else
{
if(a[k]!=null) puts("Yes");
else puts("No");
}
}
}
二、841 字符串哈希
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL; //ULL=2^64
const int N=1e5+10,P=131;
// h[i]前i个字符的hash值
// 字符串变成一个p进制数字,体现了字符+顺序,需要确保不同的字符串对应不同的数字
// P = 131 或 13331 Q=2^64,在99%的情况下不会出现冲突
// 使用场景: 两个字符串的子串是否相同
int n,m;
char str[N];
ULL h[N],p[N];
ULL get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%d%d%s",&n,&m,str+1); //字符串下标从1开始存储
p[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*P; //存储的是P的i次方 0次方时候是1
h[i]=h[i-1]*P+str[i];
}
while(m--)
{
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
}