📜  使用 Rabin Karp 算法计算字符串的不同子串(1)

📅  最后修改于: 2023-12-03 15:06:50.704000             🧑  作者: Mango

使用 Rabin-Karp 算法计算字符串的不同子串

什么是 Rabin-Karp 算法?

Rabin-Karp 算法是一种字符串匹配算法,用来在一个主字符串中查找一个子字符串的出现位置。该算法的时间复杂度为 $O(n)$,与 KMP 算法($O(n+m)$)相比,更适合处理长文本串的匹配问题。

Rabin-Karp 算法的主要思想是使用哈希函数将字符串转换为一个数字,然后在此数值上进行比较。该算法的哈希函数可以使用多种方式实现,例如把字符当作数字来看待,然后再对它们进行某种运算,如乘法、求模等等。

Rabin-Karp 算法的应用

Rabin-Karp 算法可以用于计算一个字符串中的不同子串数量。下面给出 Python 代码实现。

def calc_distinct_substrings(s: str) -> int:
    n = len(s)
    res = set()

    # 初始化值
    base = 26
    mod = 10 ** 9 + 7
    h = pow(base, n-1) % mod
    p_hash = 0
    for c in s:
        p_hash = (p_hash * base + ord(c)) % mod

    # 遍历字符串
    for i in range(n):
        res.add(p_hash)
        # 滚动更新哈希值
        if i < n-1:
            p_hash = (p_hash * base - ord(s[i]) * h + ord(s[i+1])) % mod
            h = h // base

    return len(res)

该函数输入一个字符串 s,返回不同子串的数量。它首先初始化哈希函数所需的一些值:

  • base:哈希函数的底数;
  • mod:哈希函数的模数,我们采用 $10^9 + 7$,因为它是一个质数,可以保证哈希值的唯一性;
  • h:理论上字符串首位的贡献权重,我们采用 $base^{n-1}$。

然后计算初始哈希值 p_hash,遍历字符串 s,在更新哈希值时,先删除第一位的贡献(即乘上 $base^{n-1}$ 再取模),再添加下一位的贡献(即乘上 base 再加上下一位的 ASCII 值再取模)。

最后,把每次计算出来的哈希值加入集合 res 中,最后返回集合中的元素数量,即为不同子串的数量。