哈希字符串复习

前话:这里复习一波哈希字符串,因为忘了,就是这么简单。

方法1:自然溢出法。

利用 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned long long超出 2 64 − 1 2^{64}-1 264−1会自动对其取模的特性,我们考虑用 [ 0 , 2 64 − 1 ) [0,2^{64}-1) [0,264−1)的范围的数表示一个字符串,类比二进制,我们用一个素数 p p p定义一个 p p p进制。

有: h a s h [ i ] = h a s h [ i − 1 ] × p + i d x ( s t r [ i ] ) hash[i]=hash[i-1]\times p+idx(str[i]) hash[i]=hash[i−1]×p+idx(str[i])。

i d x ( ) = s t r [ i ] − ′ a ′ + 1 idx()=str[i]-'a'+1 idx()=str[i]−′a′+1,或者直接用其 A S C I I ASCII ASCII码。

优点:常数小,时间快。

缺点:出现哈希冲突的可能性较大,错误率较大。

方法2:单值 h a s h hash hash。

考虑:用一个素数代替自然溢出法实现取模。

即: h a s h [ i ] = [ h a s [ i − 1 ] × p + i d x ( s t r [ i ] ) ] % m o d hash[i]=[has[i-1]\times p+idx(str[i])]\%mod hash[i]=[has[i−1]×p+idx(str[i])]%mod

这里给出子串 s [ l … r ] s[l\dots r] s[l…r]的 h a s h hash hash值:

h a s h l … r = ( ( h a s h [ r ] − h a s h [ l − 1 ] × p r − l + 1 % m o d ) + m o d ) % m o d hash_{l\dots r}=((hash[r]-hash[l-1]\times p^{r-l+1}\%mod)+mod)\%mod hashl…r=((hash[r]−hash[l−1]×pr−l+1%mod)+mod)%mod

相较自然溢出法,错误率更低。不过出题人可能会卡掉叫常见的素数,所以取素数建议取较大且不常见的素数。

方法3:双值 h a s h hash hash。

考虑:两个 h a s h hash hash来唯一确定一个字符串,即一个 h a s h hash hash对 < h a s h 1 , h a s h 2 > <hash_1,hash_2> <hash1,hash2>。

h a s h 1 [ i ] = ( h a s h 1 [ i − 1 ] × p + i d x ( s [ i ] ) ) % m o d 1 h a s h 2 [ i ] = ( h a s h 2 [ i − 1 ] × p + i d x ( s [ i ] ) ) % m o d 2 hash_1[i]=(hash_1[i-1]\times p+idx(s[i]))\%mod_1\\hash_2[i]=(hash_2[i-1]\times p+idx(s[i]))\%mod_2 hash1[i]=(hash1[i−1]×p+idx(s[i]))%mod1hash2[i]=(hash2[i−1]×p+idx(s[i]))%mod2

实现方法的代码:

1.自然溢出法.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
ull h[N],p[N];
int base=2333;
int main(){
scanf("%s",s+1);
int n=strlen(s+1);
p[0]=1;
for(int i=1;i<=n;i++)
p[i]=p[i-1]*base,h[i]=h[i-1]*base+(s[i]-'a'+1);
for(int i=1;i<=n;i++)
printf("h[%d]=%llu\n",i,h[i]);
int l,r;
while(cin>>l>>r){
ull val=h[r]-h[l-1]*p[r-l+1];
printf("h[%d-%d]=%llu\n",l,r,val);
}
}

哈希字符串复习_#include

2.单值 h a s h hash hash.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
ull h[N],p[N],mod=998244353;
int base=2333;
int main(){
scanf("%s",s+1);
int n=strlen(s+1);
p[0]=1;
for(int i=1;i<=n;i++)
p[i]=p[i-1]*base%mod,h[i]=(h[i-1]*base+(s[i]-'a'+1))%mod;
int l,r;
while(cin>>l>>r){
ull val=(h[r]-h[l-1]*p[r-l+1]%mod+mod)%mod;
printf("h[%d-%d]=%llu\n",l,r,val);
}
}

3.双值 h a s h hash hash.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
char s[N];
int n;
ull h1[N],h2[N],p1[N],p2[N],mod1=1e9+7,mod2=1e9+9;
ull base=2333;
void Get_Hash(ull *h,ull *p,ull mod){
p[0]=1;
for(int i=1;i<=n;i++)
p[i]=p[i-1]*base%mod,h[i]=(h[i-1]*base+(s[i]-'a'+1))%mod;
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
Get_Hash(h1,p1,mod1);
Get_Hash(h2,p2,mod2);
int l,r;
while(cin>>l>>r){
ull val1=(h1[r]-h1[l-1]*p1[r-l+1]%mod1+mod1)%mod1;
ull val2=(h2[r]-h2[l-1]*p2[r-l+1]%mod2+mod2)%mod2;
printf("h1=%llu,h2=%llu\n",val1,val2);
}
}

哈希字符串复习_i++_02