12122 . 通过滚动哈希算法求出模式串 $p$ 的哈希值 $hash\underline{}p$。
13133 . 再通过滚动哈希算法对文本串 $T$ 中 $n - m + 1$ 个子串分别求哈希值 $hash\underline{}t$。
14144 . 然后逐个与模式串的哈希值比较大小。
15- 1 . 如果当前子串的哈希值 $hash\underline{}t$ 与模式串的哈希值 $hash_p $ 不同,则说明两者不匹配,则继续向后匹配。
16- 2 . 如果当前子串的哈希值 $hash\underline{}t$ 与模式串的哈希值 $hash_p $ 相等,则验证当前子串和模式串的每个字符是否真的相等(避免哈希冲突)。
15+ 1 . 如果当前子串的哈希值 $hash\underline{}t$ 与模式串的哈希值 $hash\underline{}p $ 不同,则说明两者不匹配,则继续向后匹配。
16+ 2 . 如果当前子串的哈希值 $hash\underline{}t$ 与模式串的哈希值 $hash\underline{}p $ 相等,则验证当前子串和模式串的每个字符是否真的相等(避免哈希冲突)。
1717 1 . 如果当前子串和模式串的每个字符相等,则说明当前子串和模式串匹配。
1818 2 . 如果当前子串和模式串的每个字符不相等,则说明两者不匹配,继续向后匹配。
19195 . 比较到末尾,如果仍未成功匹配,则说明文本串 $T$ 中不包含模式串 $p$,方法返回 $-1$。
@@ -32,17 +32,17 @@ RK 算法中的滚动哈希算法主要是利用了 **「Rabin fingerprint 思
3232
3333比如 ` "cat" ` 的哈希值就可以表示为:
3434
35- $\begin{align } Hash(cat) &= c \times 26 \times 26 + a \times 26 + t \times 1 \cr &= 2 \times 26 \times 26 + 0 \times 26 + 19 \times 1 \cr &= 1371 \end{align }$
35+ $\begin{aligned } Hash(cat) &= c \times 26 \times 26 + a \times 26 + t \times 1 \cr &= 2 \times 26 \times 26 + 0 \times 26 + 19 \times 1 \cr &= 1371 \end{aligned }$
3636
3737这种按位计算哈希值的哈希函数有一个特点:在计算相邻子串时,可以利用上一个子串的哈希值。
3838
3939比如说 $cat$ 的相邻子串为 ` "ate" ` 。按照刚才哈希函数计算,可以得出 ` "ate" ` 的哈希值为:
4040
41- $\begin{align } Hash(ate) &= a \times 26 \times 26 + t \times 26 + e \times 1 \cr &= 0 \times 26 \times 26 + 19 \times 26 + 4 \times 1 \cr &= 498 \end{align }$
41+ $\begin{aligned } Hash(ate) &= a \times 26 \times 26 + t \times 26 + e \times 1 \cr &= 0 \times 26 \times 26 + 19 \times 26 + 4 \times 1 \cr &= 498 \end{aligned }$
4242
4343如果利用上一个子串 ` "cat" ` 的哈希值计算 ` "ate" ` ,则 ` "ate" ` 的哈希值为:
4444
45- $\begin{align } Hash(ate) &= (Hash(cat) - c \times 26 \times 26) * 26 + e \times 26 \cr &= (1371 - 2 \times 26 \times 26) \times 26 + 4 \times 1 \cr &= 498 \end{align }$
45+ $\begin{aligned } Hash(ate) &= (Hash(cat) - c \times 26 \times 26) * 26 + e \times 26 \cr &= (1371 - 2 \times 26 \times 26) \times 26 + 4 \times 1 \cr &= 498 \end{aligned }$
4646
4747可以看出,这两种方式计算出的哈希值是相同的。但是第二种计算方式不需要再遍历子串,只需要进行一位字符的计算即可得出整个子串的哈希值。这样每次计算子串哈希值的时间复杂度就降到了 $O(1)$。然后我们就可以通过滚动哈希算法快速计算出子串的哈希值了。
4848
@@ -94,7 +94,7 @@ def rabinKarp(T: str, p: str, d, q) -> int:
9494
9595RK 算法可以看做是 BF 算法的一种改进。在 BF 算法中,每一个字符都需要进行比较。而在 RK 算法中,判断模式串的哈希值与每个子串的哈希值之间是否相等的时间复杂度为 $O(1)$。总共需要比较 $n - m + 1$ 个子串的哈希值,所以 RK 算法的整体时间复杂度为 $O(n)$。跟 BF 算法相比,RK 算法的效率提高了很多。
9696
97- 但是如果存在冲突的情况下,算法的效率会降低。最坏情况是每一次比较模式串的哈希值和子串的哈希值时都相等,但是每一次都会出现冲突,那么每一次都需要验证模式串和子串每个字符是否完全相同,那么总的比较次数就是 $m \times (n - m + 1) $,时间复杂度就会退化为 $O(m \times n)$。
97+ 但是如果存在冲突的情况下,算法的效率会降低。最坏情况是每一次比较模式串的哈希值和子串的哈希值时都相等,但是每一次都会出现冲突,那么每一次都需要验证模式串和子串每个字符是否完全相同,那么总的比较次数就是 $m \times (n - m + 1)$,时间复杂度就会退化为 $O(m \times n)$。
9898
9999## 参考资料
100100
0 commit comments