1 Rolling Hash ADT
用
S
代表一个字符串,
- hash(S) : 表示合适的哈希函数(hash function), 用于计算 S 的哈希值(hash value).
append(c) : 将字母 c 连接(append)到字符串S 的末尾,并计算出新字符串的哈希值(hash value), 这个操作要求在 O(1) 时间内完成。-
skip(c)
: 假设字符串
S
以字母
c 开头, skip(c) 将字母 c 从字符串S 的开头去掉,并计算出新字符串的哈希值(hash value), 这个操作要求在 O(1) 时间内完成。
2 Data Structure
实现以上的抽象数据型(ADT)的数据结构如下:
-
hash(x)=u mode p
, 其中
u
是字符串
x 对应的数值(例如采用ASCII码转换方法, 字符串”abc”的数值为 979899), p 是接近于232 的大素数。 - append(c): (u⋅a+val(c))mod p=[(u modp)⋅a+val(c)]mod p , 其中 a 为字符转换为数值时候的基数,例如,采取ASCII码方式时候基数为256。
- 为了增加计算效率, 将
u mod p 和 a|x| 缓存 - skip(c): [u−val(c)⋅(a|x−1|mod p)]mod p=[(u mod p)−val(c)⋅(a|x−1|mod p)]mod p
- 有了缓存值,append() 和 skip() 方法的时间复杂度均为 O(1) 。
3 Data Structure 的伪代码实现
__init__(base, p):
hash = 0
magic = base^0 mod p = 1
//ibase 可以有多种实现方法:
//欧几里得法,费马小定理,或者调用gmpy2.invert()函数
//在后面给出示例代码
ibase = modular multiplicative inverse of base mode p
append(new):
hash = (hash * base + new) mod p
magic = (magic * base) mode p
skip(old):
hash = (hash - (old * magic) + p * base) mod p
magic = (magic * ibase) mod p
注:在
skip()
方法中计算
hash
值时候,加上额外的 (p * base)
是为了防止(hash - old * magic)
的值小于零, 如果上式小于零,在一些编程语言中求mod p后会出现负值, 实际上求mod后的值应该始终在 0 到 p 之间,所以增加 (p * base)。 加上这项并不影响结果,因为 (p * base) mod p = 0。
3.1 计算modular multiplicative inverse的方法 [1] (python)
3.1.1 欧几里得算法
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
3.1.2 费马小定理
y = x**(p-2) mod p # Pseudocode
3.1.3 gmpy module
>>> import gmpy2
>>> gmpy2.invert(0,5)
4 Karp-Rabin算法
Karp-Rabin算法使用Rolling Hash ADT实现了高效的字符串匹配, 伪代码如下:
for c in s: rs.append(c)
for c in t[:len(s)]: rt.append(c)
if rs() == rt(): ...
for i in range(len(s), len(t)):
rt.skip(t[i-len(s)])
rt.append(t[i])
if rs() == rt(): ...
其中,需要在 t 字符串中查找 s 字符串。 rs 与 rt 分别代表两个不同的 rolling hash ADT. 当rs() == rt()
时候,需要判断两个字符串是否真正相等, 避免哈希值相同而实际字符串却不相同的情况。
Reference
[1]http://stackoverflow.com/questions/4798654/modular-multiplicative-inverse-function-in-python
[2]MIT OpenCouresware 6.006 Introduction to Algorithm