📜  用于模式搜索的Rabin-Karp算法(1)

📅  最后修改于: 2023-12-03 14:56:21.758000             🧑  作者: Mango

用于模式搜索的Rabin-Karp算法

Rabin-Karp算法是一种基于哈希函数的字符串匹配算法,用于在文本串中查找一个子串的出现位置。该算法的时间复杂度为$O(n+m)$,其中$n$为文本串的长度,$m$为模式串的长度。

算法思想

Rabin-Karp算法的基本思想是通过哈希函数将模式串和文本串中的子串都转化为一个哈希值,然后比较哈希值是否相等。如果哈希值相等,则比较两个子串是否真的相等。如果相等,就说明找到了一个匹配。

为了避免哈希冲突,我们采用了一种滚动哈希的方式。假设当前正在匹配文本串的$[i, i+m-1]$子串和模式串的$[0, m-1]$子串,我们记录它们的哈希值,然后比较它们的哈希值是否相等。如果不相等,我们需要根据$[i, i+m]$子串的哈希值计算$[i+1, i+m]$子串的哈希值,这可以通过以下公式实现:

$$hash_{i+1, i+m}=d(hash_{i, i+m-1}-t_{i}h_{m-1})+t_{i+m}$$

其中:

  • $hash_{i, j}$表示文本串的$[i, j]$子串的哈希值
  • $d$和$q$是一些大于字符集大小的素数,用于取模运算
  • $t_i$表示文本串中第$i$个字符对应的数值(即$a=0,b=1,c=2,\dots$)
  • $h_m=d^{m-1}$表示模式串的哈希值
代码实现

下面是Rabin-Karp算法的基本实现,其中$pattern$表示模式串,$text$表示文本串:

def rabin_karp(pattern, text):
    """
    在文本串中查找模式串的出现位置
    """
    d, q = 256, 23333333333333 # 取模用的素数
    n, m = len(text), len(pattern)
    h, p, t = 1, 0, 0 # h为h_m, p为模式串的哈希值,t为文本串的哈希值
    for i in range(m-1):
        h = (h * d) % q
    for i in range(m):
        p = (d * p + ord(pattern[i])) % q
        t = (d * t + ord(text[i])) % q
    for i in range(n-m+1):
        if p == t:
            if pattern == text[i:i+m]:
                return i
        if i < n-m:
            t = (d * (t - ord(text[i]) * h) + ord(text[i+m])) % q
            t = (t + q) % q # 避免负数
    return -1
总结

Rabin-Karp算法虽然时间复杂度较好,但是由于哈希函数可能会导致哈希冲突,因此实际应用中需要谨慎选择哈希函数,或采用多种哈希函数进行比较。在比较短的模式串中,暴力搜索可能会更快一些,因此需要根据实际情况选择最优算法。