我目前正在阅读 Rabin Karp 算法,作为其中的一部分,我需要了解字符串多项式哈希。据我了解,字符串的哈希值由以下公式给出:
hash = ( char_0_val * p^0 + char_1_val * p^1 + ... + char_n_val ^ p^n ) mod m
在哪里:
- char_i_val:是字符的整数值加 1
string[i]-'a' + 1
- p 是大于字符集的素数
- m 是一个大素数
网站 cp-algorithms 有以下关于该主题的条目。他们说写上面的代码如下:
long long compute_hash(string const& s) {
const int p = 31;
const int m = 1e9 + 9;
long long hash_value = 0;
long long p_pow = 1;
for (char c : s) {
hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m;
p_pow = (p_pow * p) % m;
}
return hash_value;
}
我理解程序试图做什么,但我不明白为什么它是正确的。
我的问题
我无法理解为什么上面的代码是正确的。自从我做任何模块化数学以来已经有很长时间了。在网上搜索后,我看到我们有以下模加和模乘的公式:
a+b (mod m) = (a%m + b%m)%m
a*b (mod m) = (a%m * b%m)%m
基于以上内容,代码不应该如下吗?
long long compute_hash(string const& s) {
const int p = 31;
const int m = 1e9 + 9;
long long hash_value = 0;
long long p_pow = 1;
for (char c : s) {
int char_value = (c - 'a' + 1);
hash_value = (hash_value%m + ((char_value%m * p_pow%m)%m)%m ) % m;
p_pow = (p_pow%m * p%m) % m;
}
return hash_value;
}
我错过了什么?理想情况下,我正在寻求代码的细分以及为什么第一个版本是正确的解释。