字符串匹配算法之Rabin-Karp,KMP算法

Rabin-Karp算法

Rabin-Karp算法是由M.O.Rabin和R.A.Karp发明的一种基于散列的字符串查找算法。
Rabin_karp算法的思想是通过将字符串的比较转回成数字的比较。比较两个长度为m的字符串是否相等需要O(m)时间,而比较两个数字是否相等通常可以是O(1)。为了将字符串映射称对应的数字,需要用到哈希函数。

这里存在一个问题就是利用哈希函数将字符串映射成对应的数字有可能发生哈希冲突,也就是说两个字符串通过哈希函数得到数字相等,但是这两个字符不同。Rabin-Karp的解决方法是,如果两个字符串通过哈希函数得到的数字相等,还需要将这两个字符利用朴素的方法进行比较。但是如果两个字符串哈希值不同,那么这两个字符串一定不同,这就降低比较的时间。

如果哈希值冲突很少,那么该算法的时间复杂度效果很好,最坏的情况就是每一个哈希值都冲突,那么这种情况算法的复杂度跟朴素算法相同,算上计算哈希值的开销,时间复杂度还要高于朴素算法。平均情况下,Rabin-Karp算法的时间复杂度为O(n+m).

Rabin-Karp 字符串编码的本质是对字符串进行哈希,将字符串之间的比较转化为编码之间的比较。在向右滑动窗口的过程中能够以O(1)的时间复杂度计算出下一位置的哈希值。另一个需要解决的问题是整数溢出的问题,Rabin-Karp是通过除余运算来解决的。

详情请看以下两个视频:
Rabin-Karp算法讲解视频

代码如下

"""
Rabin Karp算法
t = (t-text[start-1]*aL + text[start+M-1])%modulus
"""


class RabinKarp:
    def __init__(self):
        # d是输入字符串中的字符数
        self.d = 256
        # 取余素数
        self.modulus = 101
        self.success = False

    def search(self, pat, text):
        print("pat:", pat)
        print("text:", text)
        M, N = len(pat), len(text)
        h = 0
        t = 0
        for i in range(M):
            h = (h * self.d + ord(pat[i])) % self.modulus
            t = (t * self.d + ord(text[i])) % self.modulus
        aL = 1
        for i in range(M-1):
            aL = (aL*self.d)%self.modulus

        for start in range(N - M + 1):
            if t == h:
                # 编码相同还要按个字符进行比较
                k = 0
                for i in range(M):
                    if text[start + i] != pat[i]:
                        break
                    else:k+=1
                if k == M:
                    print("匹配成功," + "pat在text中的位置是:", [start, start + M])
                    self.success = True
            if start < N-M:
                t = ((t - ord(text[start]) * aL)*self.d + ord(text[start + M])) % self.modulus

                while t < 0:
                    t += self.modulus

        if not self.success:
            print("匹配失败:text中不存在pat")

KMP算法

class KMP:
    def get_pnext(self,txt):
        """
        生成针对txt中各位置i的下一检查位置表,用于KMP算法
        """
        i, k , m = 0, -1, len(txt)
        pnext = [-1]*m
        while i<m-1:
            if k==-1 or txt[i]==txt[k]:
                i += 1
                k += 1
                if txt[i]==txt[k]:
                    pnext[i]=pnext[k]
                else:
                    pnext[i]=k     
            else:
                k = pnext[k]
        return pnext
    
    def matching_KMP(self, t, p, pnext):
        j, i = 0, 0
        n, m = len(t), len(p)
        while j < n and i < m:
            if i == -1 or t[j] == p[i]:
                j, i = j+1, i+1
            else:
                i = pnext[i]
        if i == m:
            return j-i
        return -1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值