1.用途:判断两个字符串是否相同
2.原理:将一个字符串转换成一个多项式(或者说是n进制数),将字符串映射到整数域,比较字符串就是比较数字
3.实现:
1.确定数字的进制与模数(一般模数都是一个大质数)
2.将一个字符串按照数字计算转化为一个数字
typedef unsigned long long ull;
ull base=233ull,mod=1e9+7ull;
ull hash(char *s){
ull p=0;
for(int i=1;i<=strlen(s);i++){
p=(p*base+(s[i]-'a'+1))%mod;
}
return p;
}
4.避免错误
哈希碰撞:指两个不同的字符串在经过计算后hash值相同
双哈希:将一个字符串按照不同的进制和模数取hash值两次,只有两个值都相等的时候两个字符串才相等,这样错误率就降到了两次错误率的积
typedef unsigned long long ull;
ull base=233ull,mod=1e9+7ull,base2=10001ull,mod2=1e9+9ull;
pair<ull,ull> hash(char *s){
ull p=0,ty=0;
for(int i=1;i<=strlen(s);i++){
p=(p*base+(s[i]-'a'+1))%mod;
ty=(ty*base2+(s[i]-'a'+1))%mod2;
}
return {p,ty};
}
5.子序列的hash
在hash的过程中,可以将一个字符串的子序列的哈希值都求出来
令h[x]=s[1]*base^(x-1)+s[2]*base^(x-2)+...+s[x-1]*base+s[x],h[x]代表的是s[1~x]的字符串的hash值;
要求从s[k~x]的字符串hash值,即(s[k]*base^(x-k)+s[k+1]*base^(x-k-1)+...+s[x])
容易发现,需要求的就是h[x]从s[k]后面的式子
可以利用前缀和的思想:易得h[k-1]=s[1]*base^(k-2)+s2*base^(k-3)+...+s[k-1];
所以h[x]-h[k-1]*base^(x-k+1)就是所求啦
for(int i=1;i<=strlen(s+1);i++){
h[i]=(h[i-1]*base%mod+(s[i]-'a'))%mod;
}
ans=((h[x]-h[k-1]*base*ty[h-k+1]%mod)%mod+mod)%mod;//ty数组是预处理出来的base的n次方数组