思路:
1)将字符串转化为p(经验值为131 || 13331 )进制的数 再模Q (一般取值为2^63)
2)将字符串拆分为前缀子串进行hash 计算
eg: 字符串为“ABCDE” , array : h[] 为字符串的前缀字串数组
"A": h[1] = Ascii(A) % Q; // (A)
"AB" h[2] = (Ascii(A)*p + Ascii(B))%Q; // (A*p + B)
"ABC" h[3] = (Ascii(A)*p^2 + Ascii(B) * p + Ascii(C) ) %Q; // (A*p^2 + B*p + C)
...
3)查询字符串[l,r];
由前面 的字符串前缀到 l 的hash值为h[l]
由前面 的字符串前缀到 r 的hash值为h[r]
可以得出 区间[l,r] 的字符串哈希值为:
h
[
l
,
r
]
=
h
[
r
]
−
h
[
l
−
1
]
∗
p
r
−
l
+
1
h[l,r] = h[r] -h[l-1]*p^r-l+1
h[l,r]=h[r]−h[l−1]∗pr−l+1
题目:AcWing 841
import java.util.*;
public class Main{
static int p = 131 ; // 13331
static int N = (int) 1e5+5;
static long[] h = new long[N];
static long[] po = new long[N];
public static void main(String[] args ){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
String s = sc.next();
po[0] = 1;
for(int i = 1 ; i <= n ; i ++){
h[i] = h[i-1]*p +s.charAt(i-1); // 设置前缀字符数组
po[i] = po[i-1]*p; // 设置位移权值
}
for(int i = 0 ; i < m ; i++){
int l1 = sc.nextInt();
int r1 = sc.nextInt();
int l2 = sc.nextInt();
int r2 = sc.nextInt();
long s1 = h[r1] - h[l1-1] * po[r1-l1+1]; // 计算hash值
long s2 = h[r2] - h[l2-1] * po[r2-l2+1];
if(s1 == s2 ) System.out.println("Yes");
else System.out.println("No");
}
}
}