为等长窗口计算指纹

给定长度m的模式,算法先计算模式及文本第一个m字符窗口的哈希。窗口向右移动时,移除最左字符的旧贡献,再加入新的右端字符;这样不必每次从头读取窗口中全部m个字符来重算指纹。

多项式形式可把字符当作某个基数的数位,并在一个模数下保留结果。实现预先计算移除首字符所需的幂。取模、溢出与字符表示都属于实际算法的一部分,不能把数学公式直接当作任意机器整数运算都不会出错。

参考:[1]

指纹相同后是否核对字符

若窗口指纹不同,便可排除这次匹配;指纹相同却可能只是碰撞。Princeton实现逐字符核对候选,因此不会把仅有相同哈希的不同窗口报告为精确命中,随机参数主要影响额外核对的工作量。

不再核对的Monte Carlo版本更直接,却允许碰撞造成误报。使用更多指纹或更大模数可以改变碰撞风险,并没有把有限指纹变成无限多字符串的一一对应。选择版本时应说明是否允许概率错误,而不是只写“用了哈希”。

参考:[1]

滚动成本与验证成本分开

在固定大小模运算模型下,滚动扫描本身可用O(n+m)工作;若需要逐项验证,每个候选还可能检查m个字符。碰撞或大量候选出现时,这部分工作不能忽略,精确验证版本仍可能有O(nm)最坏成本。

多个同长度模式也可以先按指纹分组,再用同一文本扫描寻找候选,不过每个指纹桶仍可能对应多个模式,最终按原字符消歧。这里的滚动哈希用于快速筛选,不是为了防止恶意伪造而设计的密码学摘要。

参考:[1] [2]