Rolling Hashes,超全解释

RollingHashes是一种字符串匹配算法,使用哈希函数快速计算字符串哈希值。它具有O(n)的时间复杂度和O(1)的空间复杂度,适用于模式匹配、最长公共子串等问题。算法基于哈希函数的均匀性和稳定性,通过滚动更新实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rolling Hashes,超全解释

Rolling Hashes 是一种字符串匹配算法。它采用哈希函数的思想,将一个字符串映射成一个整数,并使用这个整数进行比较。

Rolling Hashes 算法具有如下特点:

  • 时间复杂度为 O(n),其中 n 为字符串长度。
  • 空间复杂度为 O(1)。
  • 可以解决大部分字符串匹配问题,包括模式匹配、最长公共子串、最长回文子串等等。

本文将介绍 Rolling Hashes 的基本原理、应用场景、算法流程和优缺点等方面,希望对大家有所帮助。

基本原理

1. 哈希函数

哈希函数是将输入映射到固定大小输出的函数。它可以将一个字符串映射成一个整数,这个整数称为哈希值。

通常我们使用的哈希函数具有以下两个特点:

  • 均匀性:对于任意两个不同的输入,哈希值相等的概率很小。
  • 稳定性:对于同一个输入,哈希值相同。

常见的哈希函数包括:

  • 直接哈希法:将字符串转化为整数。
  • 幂次哈希法:将字符串看作 p 进制数,计算每一位的权值,最后求和。
  • 旋转哈希法:将字符串看作一个循环序列,对于所有可能的循环位,计算哈希值,并取最小值。

2. 滚动哈希

滚动哈希是一种快速计算字符串哈希值的方法。它利用字符串前后子串的关系,只需要 O(1) 的时间就可以计算新的哈希值。

具体来说,滚动哈希的计算方法如下:

h a s h ( s i + 1... i + m ) = d ( h a s h ( s i . . . i + m − 1 ) − s i × d m − 1 ) + s i + m hash(s_{i+1...i+m})=d(hash(s_{i...i+m-1})-s_i \times d^{m-1})+s_{i+m} hash(si+1...i+m)=d(hash(si...i+m1)si×dm1)+si+m

其中, h a s h ( s i . . . i + m − 1 ) hash(s_{i...i+m-1}) hash(si...i+m1) 表示从第 i 个字符开始长为 m 的子串的哈希值,d 表示一个常数,称为进制数,通常取一个较大的质数,例如 31、131 或 13331 等等。 s i s_i si s i + m s_{i+m} si+m 表示字符串中第 i 个字符和第 i+m 个字符。

这个式子的含义是:新的子串的哈希值等于旧的子串的哈希值乘以进制数再加上新的字符的哈希值。

滚动哈希的优劣性分析将在后面进行介绍。

应用场景

Rolling Hashes 算法广泛应用于字符串匹配问题。下面介绍 Rolling Hashes 在各个问题上的具体应用。

1. 字符串匹配

字符串匹配问题是指,给定一个文本串和一个模式串,判断模式串是否在文本串中出现过。例如,给定文本串 T T T 和模式串 P P P,判断 P P P 是否是 T T T 的子串。

Rolling Hashes 可以通过计算文本串和模式串的哈希值来解决字符串匹配问题。具体来说,我们可以先计算出模式串的哈希值,然后依次对文本串中的每个长度为模式串长度的子串计算哈希值,并将其与模式串的哈希值进行比较。如果匹配成功,则返回位置。

2. 最长公共子串

最长公共子串问题是指,给定两个字符串 s 1 s1 s1 s 2 s2 s2,找到它们的最长公共子串。例如,对于字符串 “abcde” 和 “ababcde”,它们的最长公共子串为 “abcde”。

Rolling Hashes 可以通过计算两个字符串的哈希值来解决最长公共子串问题。具体来说,我们可以先将两个字符串拼接起来,然后对于所有长度小于等于 n n n 的子串计算哈希值,其中 n n n 是字符串长度。最后,我们在两个字符串中分别查找哈希值相等的最长子串,即可找到它们的最长公共子串。

3. 最长回文子串

最长回文子串问题是指,给定一个字符串 s s s,找到它的最长回文子串。例如,对于字符串 “babad”,它的最长回文子串为 “bab” 或 “aba”。

Rolling Hashes 可以通过计算字符串反转后的哈希值来解决最长回文子串问题。具体来说,我们可以先将字符串反转后,与原字符串拼接起来,然后对于所有长度小于等于 n n n 的子串计算哈希值,其中 n n n 是字符串长度。最后,在这个字符串中查找哈希值相等的最长子串,即可找到原字符串的最长回文子串。

算法流程

Rolling Hashes 的算法流程如下:

  1. 计算模式串的哈希值。
  2. 对于文本串中每个长度为模式串长度的子串,计算其哈希值,并与模式串的哈希值进行比较。
  3. 如果匹配成功,则返回位置。

下面是 Rolling Hashes 的实现代码:

def rolling_hash(text, pattern):
    n = len(text)
    m = len(pattern)
    d = 31
    q = 10**9 + 7

    # Calculate hash of pattern
    hp = 0
    for c in pattern:
        hp = (hp * d + ord(c)) % q

    # Calculate hash of first window of text
    ht = 0
    for c in text[:m]:
        ht = (ht * d + ord(c)) % q

    # Compare hash values
    for i in range(n - m + 1):
        if ht == hp:
            if text[i:i + m] == pattern:
                return i
        if i < n - m:
            ht = ((ht - ord(text[i]) * pow(d, m-1, q)) * d + ord(text[i+m])) % q
            
    return -1

上述代码中,我们采用了取模运算的方法来避免哈希值溢出的问题。这个方法称为 “取模运算法则”,它可以保证在进行加减乘运算时,结果始终在 [ 0 , q ) [0,q) [0,q) 范围内。其中, q q q 是一个较大的质数。

优缺点

1. 优点

  • 时间复杂度为 O(n),其中 n 为字符串长度。
  • 空间复杂度为 O(1)。
  • 可以解决大部分字符串匹配问题,包括模式匹配、最长公共子串、最长回文子串等等。
  • 实现简单,易于理解。

2. 缺点

  • 当哈希值相同时,需要进行字符串比较,时间复杂度较高。因此,滚动哈希的均匀性很重要。

总结

Rolling Hashes 是一种快速计算字符串哈希值的方法,它可以解决大部分字符串匹配问题,并且实现简单,易于理解。本文介绍了 Rolling Hashes 的基本原理、应用场景、算法流程和优缺点等方面,希望对大家有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值