字符串哈希
· 4 min read
简介
该算法通过把字符串变成一个 进制数字(哈希值),实现将不同的字符串映射到不同的数字。计算方法是,对形如 的字符串,将每一位上的字符 ASCII 码乘上 的不同次方之和来计算哈希值:
注意:
- 任意字符不可以映射成 ,否则会出现不同的字符串都映射成 的情况,比如 A, AA, AAA ,经过上述公式计算后,字符串哈希值皆为 。
- 冲突问题:设置 值为 或 , 值为 ,99.99% 的概率不会冲突。(经验)
举例
现在按照上述公式举例说明字符串哈希值的计算过程:
- 输入字符串为 “ABC”
- 值为
- 值为
特性:字串完全匹配查询
假设现在拥有一个长度为 的字符串,通过字符串哈希与前缀和,仅需要 的时间,即可快速知道 与 子串是否相同。(不需要逐字符比对)
**例如:**前缀和中下标从 1 开始。设字符串 ABCDE,若想求子串 BCD 的哈希值,即 ,只需求哈希前缀 的值。
例题:1316. 不同的循环子字符串 - 力扣(LeetCode)
class Solution {
public:
unsigned long long a[2010];
unsigned long long p[2010];
int distinctEchoSubstrings(string text) {
int n = text.size();
unordered_map<unsigned long long, int> res;
memset(a, 0, sizeof a);
p[0] = 1;
for (int i = 0; i < n; i ++) {
a[i + 1] = a[i] * 131 + text[i];
p[i + 1] = p[i] * 131;
}
for (int i = 1; i <= n; i ++) { // 长度
for (int l = 1; ; l ++) { // 左端点
int r = l + i; // 右端点
if (r + i > n + 1) break;
// cout << "[" << l << " " << r << ")" << endl;
// cout << "[" << r << " " << r + i << ")" << endl;
unsigned long long hash1 = a[r - 1] - a[l - 1] * p[i];
unsigned long long hash2 = a[r + i - 1] - a[r - 1] * p[i];
// cout << hash1 << endl;
// cout << hash2 << endl;
// cout << endl;
if (hash1 == hash2) {
res[hash1] += 1;
}
}
}
return res.size();
}
};