Appearance
简介
字符串哈希
判断两个字符串是否相等,就只要判断它们的哈希值是否相等。
不局限于字符串,任何序列都可以通过字符串哈希映射成一个数值。
原理
假设所有字符串中只包含小写字符
- 将
替换为数字 ,得到一个数列;
- 将该数列看作一个
进制数(逢 进一)。
按此方法设计的哈希函数,可保证不同字符串的哈希值必不同。
字符串长度过长时,哈希值会超出 long long
的范围。
滚动哈希
为解决一般哈希函数适用范围有限的问题,采用滚动哈希。
选取两个合适的质数
按此方法设计的哈希函数,不同字符串的哈希值相同的概率很小,且哈希值不会超出 long long
的范围。时间复杂度为
cpp
typedef long long LL;
const LL b = 29, p = 10000019;
// 返回 str 的哈希值
LL getHash(string str) {
LL h = 0;
for (int i = 0; i < str.size(); i ++)
h = (h * b + str[i] - 'a') % p;
return h;
}
哈希冲突
使用 滚动哈希 时,有概率会使不同字符串的哈希值相同。该现象称为 哈希冲突。
一种降低哈希冲突概率的可靠方法是双哈希:使用两组不同的质数
cpp
typedef long long LL;
const LL b_1 = 29, p_1 = 10000019;
const LL b_2 = 31, p_2 = 10000079;
LL getHash_1(string str) {
LL h = 0;
for (int i = 0; i < str.size(); i ++)
h = (h * b_1 + str[i] - 'a') % p_1;
return h;
}
LL getHash_2(string str) {
LL h = 0;
for (int i = 0; i < str.size(); i ++)
h = (h * b_2 + str[i] - 'a') % p_2;
return h;
}
// 比较 s1 和 s2 的哈希值是否相同
bool cmp(string s1, string s2) {
return getHash_1(s1) == getHash_1(s2)
&& getHash_2(s1) == getHash_2(s2);
}