哈希表:https://oi-wiki.org/ds/hash/
目录
哈希表(一种期望算法):1.存储结构---1)开放寻址法 2)拉链法 xmodk k是一个质数且k远离2^n
O(1) 2.字符串哈希方式
添加(h[x])、查找(h[x])、删除(一般不删,开一个额外的数组,标记要删除的数组)
一、存储结构
题目来源:Acwing---840-模拟散列表
题目描述:
维护一个集合,支持如下几种操作:
I x,插入一个数 x;
Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。
输入格式
第一行包含整数 N,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为 I x,Q x 中的一种。
输出格式
对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
1≤N≤105
−109≤x≤109
输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No
1.开放寻址法
开放寻址法:添加:取mod后如果有就往后找,有空的就存里面
查找:取mod后,从前往后找,如果=x就找到,空的话就没有
删除:一般不删,开一个额外的数组,标记要删除的数组
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200003,null=0x3f3f3f3f;////N一般开两倍且为质数
int h[N];
int find(int x){ //如果x在哈希表中,返回x的位置;如果x不在哈希表中,返回x应该存储的位置
int k=(x%N+N)%N;
while(h[k]!=null&&h[k]!=x){
k++;
if(k==N)k=0;
}
return k;
}
int main(){
int n;
cin>>n;
memset(h,0x3f,sizeof h);
while(n--){
char op[2];
int x;
cin>>op>>x;
int k=find(x);
if(op[0]=='I')h[k]=x;
else{
if(h[k]!=null)puts("Yes");
else puts("No");
}
}
}
2.拉链法
#include<iostream>
#include<cstring>
using namespace std;
const int N=100003;
int h[N],e[N],ne[N],idx;
void insert(int x){
int k=(x%N+N)%N;
e[idx]=x,ne[idx]=h[k],h[k]=idx++;
}
bool find(int x){
int k=(x%N+N)%N;
for(int i=h[k];i!=-1;i=ne[i]){
if(e[i]==x)
return true;
}
return false;
}
int main(){
int n;
cin>>n;
memset(h,-1,sizeof h);
while(n--){
char op[2];
int x;
cin>>op>>x;
if(op[0]=='I')insert(x);
else{
if(find(x))puts("Yes");
else puts("No");
}
}
}
二、字符串哈希
步骤:
1.把字符串看成p进制的数(可以把字符串转换成数字)
eg:ABCD --- A:1 B:2 C:3 D:4
2.把p进制的数转换成10进制的数 eg: ABCD=1*p^3+2*p^2+3*p^1+4*p^0
3.取mod eg: ABCD=(1*p^3+2*p^2+3*p^1+4*p^0)%mod ---将ABCD映射成从0~mod-1的数
注意:1. 一般情况下:不能把某个字母映射成0 --eg: a:0 则 aa=0、aaa=0
2. 假定我们人品足够好,不存在冲突,有经验值,当p=131或者p=13331,mod取2^64,这种方式99.99%不会出现冲突。
以上哈希方式+前缀哈希的好处:可以利用前缀哈希计算出任意子串的哈希值
eg: 有一个长度为n的字符串,已知h[r],h[l-1],求l~r的hash
h[r]
h[l-1]*p^(r-l+1)//左移,和h[r]对齐
h[l~r]=h[r]-h[l-1]*p^(r-l+1)
unsigned long long 存储h,unsigned long long会溢出,相当于mod2^64。
哈希字符串作用:可以快速判断两个字符串是否相同(如下)
题目来源:Acwing---841-字符串哈希
问题描述:

代码如下:
//字符串前缀哈希法
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ULL;
const int N=100010,P=131;
int n,m;
char str[N];
ULL h[N],p[N];//h[i]: 前i个字符的哈希值,前0个字符的哈希值是0
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);
p[0]=1;
for(int i=1;i<=n;i++){
p[i]=p[i-1]*P;
h[i]=h[i-1]*P+str[i];
}
while(m--){
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2))puts("Yes");
else puts("No");
}
return 0;
}
1万+

被折叠的 条评论
为什么被折叠?



