【发布时间】:2021-09-26 21:08:12
【问题描述】:
我正在使用多项式哈希函数来计算字符串(仅由小写英文字母组成)的哈希值如下:
int SZ = 105, P = 31;
long long M = 1e12 + 9;
vector <long long> pw;
pw.resize(SZ, 1);
for(int i = 1; i < SZ; i++) {
pw[i] = (pw[i - 1] * P) % M;
}
long long calculateHash(string &s) {
long long h = 0;
for(int i = 0; i < s.length(); i++) {
h = (h + (s[i] - 'a' + 1) * pw[i]) % M;
}
return h;
}
当我必须在任何给定位置仅替换一个字符时,我不想在 O(N) 时间内重新计算整个字符串的哈希值。所以为了在 O(1) 时间内做到这一点,我做了以下操作:
long long h1 = calculateHash(s1);
long long h2 = calculateHash(s2);
// Only one character differs in `s1` and `s2` at index `idx`
// Modifying hash for h1 to incorporate s2[idx] and removing s1[idx]
h1 = (h1 + ((s2[idx] - s1[idx]) * pw[idx])) % M;
现在当我检查h1 == h2 时,理想情况下应该相等,对吧?它确实适用于较小的字符串,但有时会失败,我得到 h1 的负值,不确定这是溢出问题还是 ((s2[idx] - s1[idx]) * pw[idx]) 更负值导致 h1 低于零。
任何人都可以提出一种在仅更改一个字符时在 O(1) 时间内重新计算哈希的方法吗?提前谢谢!
【问题讨论】:
-
h1 === h2-- C++ 不是 JavaScript。 C++ 中没有“三等分”。 -
啊!怪我的macbook上的蝴蝶关键字:#
-
当我只需要替换一个字符时,我不想重新计算整个字符串的散列——这不是违背了散列函数应该做什么?以任何方式更改字符串,都应该重新计算哈希值。
-
一个问题是您使用有符号整数而不是无符号整数。使用
uint64_t而不是long long。如果您只是输出中间值:long long test = (s2[idx] - s1[idx]) * pw[idx];,您可能已经看到了这一点,并观察到它是负数。 -
哦,我注意到你的 pw 可以和 M 一样大,所以一次添加 M 是不够的,所以最好这样做:h1 = (((h1 + ((s2[ idx] - s1[idx]) * pw[idx])) % M)+M)%M;这应该总是给出正确的正模数。
标签: c++ string hash polynomials