字符串哈希
定义
定义一个把字符串映射到整数的函数 ,称为 Hash 函数。我们希望这个函数可以方便地判断两个字符串是否相等。
核心思想
将字符串视为一个 进制数,对一个大质数 取模:
例如字符串 的哈希值为 。
| 参数 | 常见取值 | 说明 |
|---|---|---|
| 基数 | 131, 233, 91138233 | 大于字符集大小的质数 |
| 模数 | , | 大质数,双哈希用两个不同模数 |
| 自然溢出 | unsigned long long | 模 ,效率高但有被卡风险 |
子串哈希 O(1) 查询
预处理前缀哈希 ,则子串 的哈希值为:
using ull = unsigned long long;
constexpr int B = 131;
constexpr ull M = 1e9 + 7;
vector<ull> h(n + 1), pw(n + 1);
pw[0] = 1;
for (int i = 1; i <= n; i++) {
pw[i] = pw[i-1] * B % M;
h[i] = (h[i-1] * B + s[i-1]) % M;
}
auto get = [&](int l, int r) {
return (h[r] - h[l-1] * pw[r-l+1] % M + M) % M;
};双哈希
用两个不同模数分别计算,两个哈希值都相等才认为字符串相同,将冲突概率降到极低。
哈希的冲突
- 生日悖论: 当比较的字符串数量 增大时,冲突概率平方级上升
- ,其中 为值域大小
- 自然溢出 在 为偶数时可被构造碰撞
- 大模数 可用双哈希抵御
应用场景
- 字符串匹配(O(n+m) 预处理 + O(1) 比较)
- 允许 k 次失配的匹配(哈希 + 二分失配位置)
- 最长回文子串(正反哈希 + 二分)
- 不同子串数量
- 最长公共子串(二分长度 + 哈希集合)
推荐练习题
| 平台 | 编号 | 名称 |
|---|---|---|
| 洛谷 | P3370 | 字符串哈希(模板) |
| 洛谷 | P2757 | 等差数列 |
| Codeforces | 1200E | Compress Words |
相关链接
内容来源:经本地化改造的 OI-wiki 字符串哈希章节。详细推导见 OI-wiki。
多平台练习
| 洛谷 | 本题单 | 竞赛基础 |
| POJ (北大) | PKU JudgeOnline | 经典题目,适合巩固 |
| HDU (杭电) | HDU OJ | 暑期多校训练 |
| Codeforces | Codeforces | 国际竞赛,适合提升 |