KMP 算法 python

主要思想:当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。如何记录已经匹配的内容时kmp算法的重点。

解决问题:利用前缀表解决字符串匹配问题(一个字符串中是否出现另一个字符串)

暴力解法:两层for循环,时间复杂度O(m*n)

前缀:包含首字母不包含尾字母的所有字符串组合

后缀:包含尾字母不包含首字母的所有字符串组合

最长相等前后缀:

例:aabaaf

前缀字符串最长相等前后缀数量(前缀表)解释
a0没有前后缀
aa1从前和后数只有a相同
aab0前后不相同
aaba1前a和后a相同
aabaa2前a和后a相同,前aa和后aa相同
aabaaf0首字母a和尾字母f不同

 那么其前缀表为next = [0, 1, 0, 1, 2, 0]

假设两个字符串,主串"mississippi",  待匹配串"issip",判断主串中是否包含待匹配串。

1.首先构建待匹配串的前缀表

2.根据前缀表判断主串中是否包含待匹配串

那么步骤一中如何构建字符串的前缀表:

def getnext(str2):                               # str2要创建前缀表的字符串参数
        b = len(str2)            
        next = [0 for _ in range(b)]             #定义好next空数组
        j = 0                                    #前缀初始位置,同时也是相等前后缀的长度
        for i in range(1,b,1):                   #后缀指针位置变化
            while j > 0 and str2[j] != str2[i]:  #判断前后缀初始位置不相等退回发生分歧的位置
                j = next[j-1]                    #j = 0 时,前缀表只能是next = [0]
            if str2[j] == str2[i]:              
                j += 1
            next[i] = j                          #不仅记录旧的子串的相等前后缀,也记录新的
        return next 

  待匹配串"issip" 的前缀表为next = [0, 0, 0, 1, 0],试验一下:

print(getnext('issip'))
>>> [0, 0, 0, 1, 0]

如何步骤2中根据前缀表判断主串中是否包含待匹配串呢?

思路:按顺序匹配两个字符串当两个字符串出现不匹配字母时,找到待匹配串不匹配字母的前一个字母,找到前缀表中最大的数,并以此为下标在待匹配串中继续与查找串中不匹配点进行匹配。

a = len(str1)
b = len(str2)
        
j = 0                                            #待匹配串的指针位置
next = self.getnext(str2)
for i in range(a):                               #主串的指针位置
    while j > 0 and str1[i] != str2[j]:          #与创建前缀表思想相似,若产生分歧,则待匹配串                                                                    
        j = next[j-1]                            #倒退回产生分歧的位置   
    if str1[i] == str2[j]:
        j += 1

整体代码如下:若存在则返回主串中穿线待匹配串位置的第一个下标,若待匹配串为空,则返回0,否则返回-1

class Solution(object):
    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        a = len(haystack)
        b = len(needle)
        if b == 0:
            return 0
        j = 0
        next = self.getnext(needle)
        print(next)
        for i in range(a):
            while j > 0 and haystack[i] != needle[j]:  
                j = next[j - 1]
            if haystack[i] == needle[j]:
                j += 1
            if j == b:
                return i - j + 1

        return -1

    def getnext(self, needle):
        b = len(needle) 
        next = [0 for _ in range(b)]  
        j = 0
        for i in range(1, b, 1):  
            while j > 0 and needle[j] != needle[i]:  
                j = next[j - 1]
            if needle[j] == needle[i]: 
                j += 1
            next[i] = j  
        return next

#测试
s = Solution()
print(s.strStr("mississippi","issip"))

#输出
>>> 4

参考链接:

https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值