视频讲解AcWing 841. 字符串哈希 - AcWing
全称字符串前缀哈希法,把字符串变成一个p进制数字(哈希值),实现不同的字符串映射不同的数字
对形如 X1X2X3⋯Xn−1Xn 的字符串,采用字符的ascii 码乘上 P 的次方来计算哈希值。
映射公式
比较不同区间的子串是否相同,就转化为对应的哈希值是否相同
求一个字符串的哈希值就相当于求前缀和,
求一个字符串的子串的哈希值就相当于求区间和
区间和公式的理解: ABCDE 与 ABC 的前三个字符值是一样,只差两位,
乘上P的二次方把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。
使用:typedef unsigned long long,得到的哈希值就不用取模了,因为unsigned long long会把溢出的部分自动取模
#include<iostream> #include<cstdio> #include<string> using namespace std; typedef unsigned long long ULL; const int N = 1e5+5,t = 131;//131 13331(经验值) ULL h[N],p[N]; // h[i]前i个字符的hash值 // 字符串变成一个p进制数字,体现了字符+顺序,需要确保不同的字符串对应不同的数字 // t = 131 或 13331 在99%的情况下不会出现冲突 // 使用场景: 两个字符串的子串是否相同 ULL query(int l,int r){ return h[r] - h[l-1]*p[r-l+1]; } int main(){ int n,m; cin>>n>>m; string x; cin>>x; //字符串从1开始编号,h[1]为前一个字符的哈希值 p[0] = 1; h[0] = 0; for(int i=1;i<=n;i++){ p[i] = p[i-1]*t; h[i] = h[i-1]*t +x[i]; //前缀和求整个字符串的哈希值 } while(m--){ int l1,r1,l2,r2; cin>>l1>>r1>>l2>>r2; if(query(l1,r1) == query(l2,r2)) printf("Yes\n"); else printf("No\n"); } return 0; }