Rabin-Karp ( 字符串匹配 )详解

字符串匹配,例从 字符串S 中( 长度为 n ),找到 字符串T ( 长度为 m )

经典思路:遍历 字符串 S,对于每个都为起点,匹配一次,则 O( n m )的复杂度
但是这样我们就对 字符 重复判断了多次
请添加图片描述

那我们应该怎么处理才能避免多次对同一个字符判断呢?
我们先考虑假如 字符串S 和 字符串T 是由数字组成
例如 S 为 “19735859734”,T 为 “973”
第一次比较 197 和 973
第二次比较 (197 - 1 * 100)* 10 + 3 = 973 和 973
第三次比较 (973 - 9 * 100)* 10 + 5 = 735 和 973
第四次…

这样我们就可以从头到尾以 O( n )的复杂度处理

这样为什么可行呢,因为这个是 十进制 的,每位上的数,都可以代表清晰表示第几个字符是什么
那我们推广这种思路,我们是否只要把 十进制 改为 B 进制( B 大于等于 字符的种类),这样每位上的数也能表达第几个字符是什么

如果字符种类比较多可以把 B 取大一点,但这样我们可能需要对 h 取模,毕竟 B 的 m 次方,防止溢出,因为我们只要比较不同就行,不用比较大小,所以可以取模( 注意 B 与 h 要互素 )

注意一下:有可能不同字符的哈希值相同,如果发生这种情况,我们还需要进行朴素的检查( 即一个个字符比较 ),这种可能会导致复杂度退化为 O( n m ),但我们在竞赛题中,只用比较哈希值就行

实现代码如下( 比较 字符串b 中有几个 字符串a ):

const int B = 128;
int compare(string a, string b)
{
    int res = 0;
    int al = a.length(), bl = b.length(), t = 1;
    if(al > bl) return 0;
    for(int i = 0; i < al; i++)
    {
        t = t * B;
    }
    int ah = 0, bh = 0;
    for(int i = 0; i < al; i++)
    {
        ah = ah * B + a[i];
        bh = bh * B + b[i];
    }
    for(int i = 0; i + al <= bl; i++)
    {
        if(ah == bh) res++;
        if(i + al < bl) bh = bh * B + b[i+al] - b[i] * t;
    }
    return res;
}
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
匹配是指在一个文本串中查找另一个模式串的过程。常用的串匹配算法有Naïve算法、Rabin-Karp算法和Knuth-Morris-Pratt算法。 1. Naïve算法 Naïve算法是最简单的串匹配算法,也称为暴力匹配算法。它的思路是从文本串的第一个字符开始,依次比较文本串中的每个字符是否与模式串中的字符相等。若不相等,则继续向后比较;若相等,则比较下一个字符,直到找到完全匹配的子串或文本串被匹配完为止。 Naïve算法的时间复杂度是O(mn),其中m和n分别是模式串和文本串的长度。当模式串和文本串长度相等时,最坏情况下时间复杂度达到O(n^2)。 2. Rabin-Karp算法 Rabin-Karp算法是一种基于哈希值的串匹配算法。它的思路是先将模式串和文本串都转换为哈希值,然后比较它们的哈希值是否相等。如果哈希值相等,则再逐个比较模式串和文本串中的字符是否相等。这种方法可以有效地减少比较次数,提高匹配效率。 Rabin-Karp算法的时间复杂度是O(m+n),其中m和n分别是模式串和文本串的长度。但是,由于哈希函数的不完全性和哈希冲突的存在,Rabin-Karp算法在某些情况下可能会出现误判。 3. Knuth-Morris-Pratt算法 Knuth-Morris-Pratt算法是一种基于前缀函数的串匹配算法。它的思路是先计算出模式串的前缀函数,然后利用前缀函数的信息来跳过已经匹配过的部分,减少比较次数。 具体来说,KMP算法匹配过程中维护一个指针i和一个指针j,其中i指向文本串中当前匹配的位置,j指向模式串中当前匹配的位置。如果当前字符匹配功,则i和j同时向后移动一位;如果匹配失败,则通过前缀函数计算出j需要跳转到的位置,使得前j-1个字符与文本串中的对应字符已经匹配功,然后将j指向这个位置,i不变,继续比较下一个字符。 KMP算法的时间复杂度是O(m+n),其中m和n分别是模式串和文本串的长度。由于利用了前缀函数的信息,KMP算法可以在最坏情况下达到O(n)的时间复杂度,比Naïve算法和Rabin-Karp算法更加高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值