字符串哈希
字符串哈希
可以快速判断字符串是否相同(比KMP还快)
字符串前缀哈希法
先预处理出来所有前缀的哈希
str = "ABCDEFGHI";
h[0] = 0;
h[1] = "A"; // 哈希值
h[2] = "AB";
h[3] = "ABC";
h[4] = "ABCD";
...
求字符串哈希值的方法是将字符串看成一个p进制的数:
"ABCD"
第一位的数是:A - 1
第二位的数是:B - 2
第三位的数是:C - 3
第四位的数是:D - 4
则p进制数对应的十进制数为$(1\ 2\ 3\ 4)_p = (1\times p^3 + 2\times p^2 + 3\times p^1 + 4\times p^0)\mod{q} $
因为字符串可能很长,导致数字很大,所以最后要mod上一个比较小的数字q,映射到\(0\sim q-1\)
注:
- 第一步字符映射中不能映射成0,如\(A_p - 0\),则\(AA_p - 0\)
- 该方法不考虑冲突情况
经验:p = 131 或 13331,q = \(2^{64}\)
由此可以求出任何子段的哈希值:
\[\begin{aligned}
& h[R]\quad p^R\dots p^0 \\
& h[L-1]\quad p^{L-1}\dots p^0 \\
& \text{将其对齐:} \\
& h[R]\quad p^R\dots p^0 \\
& h[L-1]\times p^{R-L+1}\quad p^{R}\dots p^{R-L+1} \\
& \text{故最终公式为:}h[R]-h[L]\times p^{R-L+1}
\end{aligned}
\]
h数组使用unsigned long long
类型,溢出也就相当于取模了
typedef unsigned long long ULL;
const int N = 100010, P = 131;
char str[N];
ULL h[N], p[N];
// p数组预处理P的多少次方
// h数组为个长度子串哈希
ULL get(int l, int r) { // 获取任意子串的哈希值
return h[r] - h[l - 1] * p[r - l + 1];
}
p[0] = 1;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + str[i];
}