多项式滚动哈希
多项式滚动哈希是一种将字符串映射为高进制整数的高效算法;它利用数学递推特性,能在 $O(1)$ 时间内“滚动”计算出任意子串的哈希值,广泛用于字符串匹配和查重。
数据结构1分钟阅读

多项式滚动哈希 (Polynomial Rolling Hash) 是一种常用于字符串匹配、重复子串查找等场景的字符串哈希算法。它的核心思想是将一个字符串看作是一个高进制的数字,并将其映射为一个整数(哈希值)。
通过巧妙的数学性质,它能够在 的时间内计算出任意子串的哈希值,从而极大地提高字符串处理的效率(例如在 Rabin-Karp 字符串匹配算法中)。
对于一个长度为 的字符串 ,我们可以选择一个基数 (Base) 和一个模数 (Mod) ,将其转化为如下的多项式值:
其中:
- :字符的数值(通常取其 ASCII 码,例如
'a'为 1 或 97,为避免冲突建议从 1 开始)。 - (基数):通常取一个大于字符集大小的质数(例如小写字母场景常取 或 )。
- (模数):为了防止溢出并保证哈希值在安全范围内,通常取一个很大的质数(例如 或 )。
如果我们要暴力计算一个字符串所有子串的哈希值,复杂度会达到 。而滚动哈希的精髓在于递推:
假设已知子串 的哈希值为 ,当我们把窗口向右移动一位,去掉最左边的字符 并加入右边的新字符 时,我们不需要重新计算整个多项式,只需进行简单的数学运算:
- 减去最高位字符的影响:
- 整体向左进一位(乘以基数 ):
- 加上新加入的最低位字符:
这样,新子串的哈希值就可以在 时间 内计算出来。
下面是一个使用多项式滚动哈希查找子串的简单实现:
def polynomial_rolling_hash(s, pattern): n, m = len(s), len(pattern) if n < m: return -1
P = 131 MOD = 10**9 + 7
# 计算 P^(m-1) % MOD p_pow = 1 for _ in range(m - 1): p_pow = (p_pow * P) % MOD
# 计算 pattern 和 s 中第一个窗口的哈希值 pattern_hash = 0 current_hash = 0 for i in range(m): pattern_hash = (pattern_hash * P + ord(pattern[i])) % MOD current_hash = (current_hash * P + ord(s[i])) % MOD
if current_hash == pattern_hash: return 0
# 滚动哈希滑动窗口 for i in range(n - m): # 移除最高位,乘以 P,加上新最低位 current_hash = ( (current_hash - ord(s[i]) * p_pow) * P + ord(s[i + m]) ) % MOD # Python 的求模对负数同样适用,但为了安全可以加上 MOD current_hash = (current_hash + MOD) % MOD
if current_hash == pattern_hash: return i + 1
return -1- 高效:预处理 ,单次查询或滚动更新 。
- 实现简单:代码量少,常用于竞赛编程(如字符串哈希、最长回文子串、重复子串等)。
- 理论上存在哈希碰撞的风险(即不同的字符串算出了相同的哈希值)。
- 应对策略:
- 使用双哈希(选用两组不同的 和 分别计算,两个都相等才认为字符串相同),将碰撞概率降到最低。
- 使用自然溢出(利用无符号 64 位整数溢出作为隐式取模),但需警惕精心构造的恶意碰撞数据。