【问题标题】:Modify hash value on replacing a single character in string (c++)在替换字符串中的单个字符时修改哈希值(c ++)
【发布时间】: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


【解决方案1】:

原则上你改变结果值的想法是正确的,但你需要的是一个模运算符,它的结果总是正的,对于负输入数字也是如此。

要使用 C++ 模模拟此行为,您可以执行以下操作:

long long tmp=(h1 + ((s2[idx] - s1[idx]) * pw[idx])) % M;
h1=(tmp+M)%M;

第一行与您所做的操作相同,第二行使结果为正,因为在 C++ 模运算之后 tmp 不能小于 -M。即使tmp 已经是正数,也需要额外的模数以确保该数字保持小于M

【讨论】:

    猜你喜欢
    • 2017-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 2011-11-19
    • 2019-07-29
    相关资源
    最近更新 更多