字符串哈希
算法:
取一个固定值P,把字符串看作p进制数,并分配一个大于0的数值,代表每种字符,一般来说,我们分配的数值都有远小于p。
一般来说p取131或13331,此时hash的冲突率极低,只要hash值相同,我们就认为原字符串是相等的。
实战演练:
对于一串字符串:asdfasdjgjkhasd
选取p为131我们用1代表a,2代表b,以此类推,那么我们对于每一个位都用p进制表示出来,比如;第一位是a,也就是1,这样1就可以表示a这个一个字符的字符串,那么如果字符串是as怎么表示呢,与数学的进制相同
(例:比如1101是二进制的数,怎么表示成十进制的数呢,一位的1可以用十进制的1表示,那么11怎么表示呢,用12+1即可,那么110怎么表示呢,用二位的再加上最后的0即可,则为(1 2+1)2+0,那么1101呢,以此类推,再把前三位的数2+1即可;则((1*2+1)*2+0)*2+1)=11;
理论上讲,这相当于把前面n位的数左移m位,加上m位数,就能变成n位后面再加m位的值了,上面的例子就是n和m为1 的时刻;
)
操作:
1.我们可以通过左移再加数操作完成字符串的hash值的求取;求得以后即可以通过比较hash值的大小来判断是否相等;
2.对于一个长字符串可以通过前缀和求任意一段的字符的hash值,首先用前缀和表示出任意一位p进制的基数,即p的n次方,求字符串arr[l~r]的哈希值的时候即可用(f [ r ] - f [ l - 1 ] * p [ r - l + 1 ]);(f里面是 f[ 0 ~ i ] 的字符串的哈希值);这样即可实现该操作,然后再通过1操作即可实现目的;
例题
#include<unordered_set>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1010;
char s[1000100];
unsigned long long f[1000010],p[1000010];
int main(){
scanf("%d",s+1);
int n=strlen(s+1),q;
scanf("%d",&q);
p[0]=1;
for(int i=1;i<=n;i++){
f[i]=f[i-1]*131+s[i]-'a'+1;
p[i]=p[i-1]*131;
}
for(int i=0;i<q;i++){
int l1,l2,r1,r2;
cin>>l1>>r1>>l2>>r2;
if(f[r1]-f[l1-1]*p[r1-l1+1]==f[r2]-f[l2-1]*p[r2-l2+1]){
puts("Yes");
}
else puts("No");
}
return 0 ;
}