哈希字符串复习
前话:这里复习一波哈希字符串,因为忘了,就是这么简单。
方法1:自然溢出法。
利用 超出 会自动对其取模的特性,我们考虑用 的范围的数表示一个字符串,类比二进制,我们用一个素数 定义一个 进制。
有: 。
,或者直接用其 码。
优点:常数小,时间快。
缺点:出现哈希冲突的可能性较大,错误率较大。
方法2:单值 。
考虑:用一个素数代替自然溢出法实现取模。
即:
这里给出子串 的 值:
相较自然溢出法,错误率更低。不过出题人可能会卡掉叫常见的素数,所以取素数建议取较大且不常见的素数。
方法3:双值 。
考虑:两个 来唯一确定一个字符串,即一个 对 。
实现方法的代码:
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);
}
}
2.单值 .
#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.双值 .
#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);
}
}