算法—KMP算法

一、KMP算法

T:"baaccabaaccabc"

P:"aacca"

第一步,先维护好最长公共前缀表。

        a           0  (前后字符相等的个数)

        aa         1

        aac       0 

        aacc     0

        aacca   1

最前面补个-1,最终得到      a   a   c   c   a

                                           -1   0    1   0   0   1   #应用时,对应1~5

代码实现:

def getpnext(self, sub):
    #双指针法,建立出pnext表
    p, n = 0, len(sub)
    pnext = [0]*n #对应
    i = 1 #单字符默认为0,不用再比较
    while i<n:
        if sub[i] == sub[p]:
            pnext[i] = p+1 #记录值
            p += 1    #递增继续比较下一个
            i += 1
        elif p != 0: #值不相等,但是之前有相等的,p需要从头开始比较起
            p = pnext[p-1]
        else:    #值不等且p回到头部时,重新比较时,i到下一位
            pnext[i] = 0
            i += 1
    return pnext

代入 "aacca"时,返回pnext=[0, 1, 0, 0, 1]

第二步,遍历表,根据pnext进行移动匹配。

def kmp(self, s, sub):
    n = len(s)
    m = len(sub)
    pnext = self.getpnext(sub) #拿到最长公共前后缀表
    ret = []
    i, j = 0, 0 #同时遍历2个字符串
    while i<n:  #遍历主串为主,主串中可能存在多个子串
        if s[i] == sub[j]:
            i += 1
            j += 1
        elif j != 0:  #子串存在部分匹配的情况时,借助pnext跳过逐个比较
            j = pnext[j-1]  #对应j-1
        else:
            i += 1    #不存在部分匹配,i直接下一位

        #考虑子串已匹配到的情况,主串还存在多个子串。
        if j == m:  #子串匹配到
            ret.append(i-j) #记录匹配子串的起始位置
            j = 0 #子串重新开始,主串i上面步骤已经移位
        
        #优化步骤:剩余主串长度,已不够剩余子串匹配时,直接退出。
        if n-i-1 < m-j-1:
            break
    return ret

输入: "baaabcaabc", "aabc"

输出: [2, 6]

二、字符串匹配问题

s:"abcbcdedefg"    

sub: "bcde"

将s串中含有sub串的部分剔除。

注意:剔除一次后,s:"abcdefg"  扔有sub串,继续剔除

1、暴力匹配的方法,利用库函数:

    def DelDupStr(self, s, sub):
        if not s or not sub:
            return
        n = len(sub)
        while sub in s:
            if sub in s:
                index = s.index(sub)
                s = s[:index] + s[index+n:]
            else:
                break
        return s, sub

2、KMP算法匹配,简化时间复杂度

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值