AcWing 841. 字符串哈希<分析过程>
原题链接
简单
作者:
一万小时定律
,
2022-06-27 08:23:52
,
所有人可见
,
阅读 409
字符串哈希
O(n)+O(m)O(n)+O(m)
字符串前缀哈希法,把字符串变成一个p进制数字(哈希值),实现不同的字符串映射到不同的数字。
对形如 X1X2X3⋯Xn−1XnX1X2X3⋯Xn−1Xn 的字符串,采用字符的ascii 码乘上 P 的次方来计算哈希值。
映射公式 (X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ(X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ
注意点:
1. 任意字符不可以映射成0,否则会出现不同的字符串都映射成0的情况,比如A,AA,AAA皆为0
2. 冲突问题:通过巧妙设置P (131 或 13331) , Q (2的64次方)的值,一般可以理解为不产生冲突。
问题是比较不同区间的子串是否相同,就转化为对应的哈希值是否相同。
求一个字符串的哈希值就相当于求前缀和,求一个字符串的子串哈希值就相当于求部分和。
前缀和公式 h[i+1]=h[i]×P+s[i] i∈[0,n−1]i∈[0,n−1] h为前缀和数组,s为字符串数组
区间和公式 h[l,r]=h[r]−h[l−1]×P的r−l+1次方
区间和公式的理解: ABCDE 与 ABC 的前三个字符值是一样,只差两位,
乘上 P的2次方 把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5 +5 ,P=131;
ll h[N],p[N];
// h[i]前i个字符的hash值
// 字符串变成一个p进制数字,体现了字符+顺序,需要确保不同的字符串对应不同的数字
// P = 131 或 13331 Q=2^64,在99%的情况下不会出现冲突
// 使用场景: 两个字符串的子串是否相同
ll query(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}//求子串对象hash值
int main(){
int n,m;
cin>>n>>m;
string x;
cin>>x;
//字符串从1开始编号,h[1]为前一个字符的哈希值
p[0]=1;
h[0]=0;
for(int i=0;i<n;i++){
p[i+1]=p[i]*P;
h[i+1]=h[i]*P+x[i];//前缀和求整个字符串hash值
}
while(m--)
{
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(query(l1,r1)==query(l2,r2))
puts("Yes");
else
puts("No");
}
return 0;
}
👍