📌  相关文章
📜  使用多项式滚动哈希函数数组中存在的不同字符串(1)

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

使用多项式滚动哈希函数数组中存在的不同字符串

前言

在计算机科学中,哈希函数是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。哈希函数是密码学的主要组件之一,用于验证数据的完整性和数字签名。多项式滚动哈希函数是一种常用的哈希函数,可以用于哈希表、字符串匹配等一系列应用中。

本文将介绍如何使用多项式滚动哈希函数数组来求解存在于不同字符串中的字符串。

需求

假设我们有多个字符串,要求找出其中存在的相同子串。

解决方案

一种简单的解决方案是枚举每个子串,然后使用 hash 函数对其进行哈希,对于匹配的子串,它们将返回具有相同哈希值的哈希值。这种方法的时间复杂度为 $O(n^3)$,其中 $n$ 是字符串的长度。

而如果我们使用多项式滚动哈希函数数组,可以将时间复杂度降低到 $O(n^2)$。

多项式哈希

多项式哈希是一种常用的字符串哈希算法。设 $S_i$ 为字符串 $S$ 的第 $i$ 个字符,则字符串 $S$ 的哈希值 $H(S)$ 可以表示为:

$$H(S) = \sum_{i=0}^{|S|-1} S_i p^i \pmod m$$

其中 $p$ 和 $m$ 是两个选择的质数。质数选择的好坏对于哈希的性能有非常重要的影响。

对于上述哈希函数,时间复杂度为 $O(|S|)$。参数 $p$ 和 $m$ 的选择旨在使两个不同字符串的哈希值之间的冲突概率非常小。实际中,我们可以使用多个选择不同的 $p$ 和 $m$,并针对每个 $p$ 和 $m$ 都计算出一个哈希值。这些哈希值放在一个哈希函数数组中,可以提高哈希函数的效率和准确性。

多项式滚动哈希

多项式滚动哈希是一种常用的字符串哈希算法,可以在不重新计算字符串的情况下快速计算字符串的哈希值。在找到字符串中的相同子串时非常有用。

假设我们要计算字符串 $S$ 的哈希值。我们已经计算出了 $H(S_0 … S_k)$,现在要计算 $H(S_1 … S_{k+1})$。通过简单的代数运算,可以得到:

$$H(S_1 … S_{k+1}) = (H(S_0 … S_k) - S_0p^k) \times p + S_{k+1} \mod m$$

这个等式的意思是,将 $H(S_0 … S_k)$ 减去 $S_0p^k$,这样我们就得到了 $S_1…S_k$ 的哈希值。此外,我们将其与 $S_{k+1}$ 相乘,然后添加到当前的哈希值中。这个过程保证了计算机地修改字符串的哈希值,而不需要重新计算整个哈希。这可以帮助我们在不重新计算字符串的情况下,快速地计算字符串的哈希值,对于找到字符串中的相同子串是非常有用的。

寻找相同子串

我们可以使用多项式滚动哈希函数数组来寻找任意两个字符串中的相同子串。基本思路是将所有字符串插入到哈希表中,如果遇到具有相同哈希值的字符串,则它们是相同的。

from collections import defaultdict

def RollingHash(strs):
    p, m = 31, 10 ** 9 + 9

    def _hash(s):
        h = 0
        for c in s:
            h = (h * p + ord(c)) % m

        return h

    hashes = defaultdict(list)

    for s in strs:
        for i in range(len(s)):
            hashes[_hash(s[i:])].append((s, i))

    res = []
    for k, v in hashes.items():
        if len(v) > 1:
            res.append([s[i:i + len(k)] for s, i in v])

    return res
结语

多项式滚动哈希函数是一种非常有用的数据结构,在字符串匹配、哈希表等一系列应用中都有广泛的应用。在本篇文章中,我们介绍了多项式哈希、多项式滚动哈希以及如何使用多项式滚动哈希函数数组来寻找存在于不同字符串中的相同子串。