字符串Hash概念
简单来说,字符串Hash就是将一串字符串转化为数字,一种字符串对应一个数字,那么在比较两个字符串是否相同,就只需要比较一次数字,不必一个一个字符的比较。
Hash公式
hash[i]=(hash[i−1])∗p+idx(s[i]) % mod
idx(s[i]) =s [ i ]− ‘a’ + 1(也可以用该字符的ASCII值)
其中p和mod均为质数,且有p<mod。
自然溢出法
利用unsigned long long的范围自然溢出
unsigned long long Hash[n]
hash[i]=hash[i−1])∗p+idx(s[i];
相当于已经对 2的64次方-1 进行取模
求子串的hash值
如果已知一个字符串 s1s2s3s4的hash值,怎么求s2s3的hash值
hash[1]=s1
hash[2]=s1∗p+s2
hash[3]=s1∗p2+s2∗p+s3
hash[4]=s1∗p3+s2∗p2+s3∗p+s4
从上式我们不难看出,s2s3的hash值为s2*p+s3
我们可以归纳出结论
hash = hash[ y ] - hash [x - 1]p^(y - x + 1)
(通常p取131或者1331)
例题
代码实现
#include<stdio.h>
#include<string.h>
unsigned long long h[1000010] ,p[1000010];
unsigned long long hash(int l,int r)
{
return (h[r]-h[l-1]*p[r-l+1]);//子串公式
}
int main()
{
char str[1000010];
while(scanf("%s",str)!=EOF)
{
h[0]=0;//计算h[1]时,h[0]必须要赋值,
p[0]=1;
int i,len;
len=strlen(str)+1;
for(i=len;i>=0;i--)
str[i]=str[i-1];//hash值从1开始,所以把字符串从1开始存
for(i=1;i<=len;i++)
{
h[i]=h[i-1]*131+str[i]-'a'+1;
p[i]=p[i-1]*131;
}
int n;
scanf("%d",&n);
while(n--)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(hash(l1,r1)==hash(l2,r2))
printf("Yes\n");
else
printf("No\n");
}
}
return 0;
}