使用场景: 两个字符串的子串是否相同
字符串哈希又叫做字符串前缀哈希法,把字符串变成一个p进制的数字(哈希值),实现不同的字符串映射到不同的数字。对形如 X1X2X3⋯Xn−1Xn 的字符串,采用字符的ascii 码乘上 P 的次方来计算哈希值。
映射公式 (X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ
例题
给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2请你判断[l1,r1]和[l2,r2]这两个区间所包含的字符串子串是否完全相同。
字符串中只包含大小写英文字母和数字。
输入格式
第一行包含整数n和m,表示字符串长度和询问次数。
第二行包含一个长度为n的字符串,字符串中只包含大小写英文字母和数字。
接下来m行,每行包含四个整数l1,r1,l2,r2表示一次询问所涉及的两个区间。
注意,字符串的位置从1开始编号。
输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出“Yes”,否则输出“No”。
每个结果占一行。
数据范围
1≤n,m≤105
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
typedef unsigned long long ULL;
const int N=1e5+10,p=131; //p等于131或者13331可以最的化的避免冲突
ULL h[N],k[N]; //h[i]存前i个字符的哈希值
char s[N];
ULL get(int l,int r){
return h[r]-h[l-1]*k[r-l+1];5
}
int main(){
int n,m;
cin>>n>>m;
cin>>s+1;
k[0]=1;
for(int i=1;i<=n;i++){
k[i]=k[i-1]*p;
h[i]=h[i-1]*p+s[i]; //处理前缀和
}
while(m--){
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1)==get(l2,r2))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}