kmp算法

本文深入探讨了KMP算法,一种用于高效解决字符串匹配问题的算法。通过避免暴力匹配时的完全回退,KMP算法实现了O(n+m)的时间复杂度。文中详细解释了KMP算法的工作原理,特别是next数组的计算过程,并给出了LeetCode第28题的完整解决方案。通过递推方式求解next数组,使得在字符串失配时能快速确定匹配指针的移动位置,从而优化了匹配效率。
摘要由CSDN通过智能技术生成

解决的问题

kmp算法是用于解决字符串匹配问题的算法。具体问题是:现有一个长度为n的字符串s和一个长度为m的字符串p,现在要求给出p在s中第一次出现的下标。
可以看看leetcode的第28道题
传统的暴力方法就是两重循环来求解那么时间复杂度就是O(n*m),但是使用kmp算法的时间复杂度是O(n+m)

具体的原理

传统的暴力匹配规则在匹配失败的时候会将p串完全回退到最开始的地方,如下图
在这里插入图片描述

在这里插入图片描述
也就是说在暴力方法里面,匹配失败之后i会回退到开始匹配的下一个字符的位置,j会直接回退到0

但如果是kmp会怎么处理?
在这里插入图片描述
在这里插入图片描述
可以看到i并没有回退,而j则是回退到下标1。这是因为当p串中的D不匹配时,会有一个隐藏的信息,即D字符前面的ABA是匹配的,而对于ABA这个字符串来说,它的前缀和后缀中相等的最大串是A,所以j只用移动到这个前缀串的下一位即可。

那么我们只用求得p串中,每一位的移动位置就能解决p串和s串失配时j该移动的位置的问题。所以现在问题就变成了如何求解p串中每一位的移动位置。

首先定义next[x]就是在p[x]失配时,j应该移动到的位置。考虑采用递推的方式去求解,即如果目前已知了next[0]、next[1]…next[x-1],如何去求next[x]。为了描述方便,将next[x-1]记做now

  • 第一种情况,如果p[x]==p[now],那么显然可以让next[x]=now+1
    在这里插入图片描述
  • 第二种情况,如果p[x]!=p[now],这时我们需要减少now,具体要减少到多少呢?
    在这里插入图片描述
    我们可以看到上图中的子串A和子串B是相同的,所以应该将now改为next[now-1],这里的意思就是在子串A上继续进行自匹配的过程。
    在这里插入图片描述
    具体的求解next数组的代码即可写作:
def getNext(needle):
    nxt = [0]
    x = 1
    now = 0
    while x < len(needle):
        if needle[x] == needle[now]:
            nxt.append(now + 1)
            x += 1
            now += 1
        elif now:
            now = nxt[now - 1]
        else:
            nxt.append(0)
            x += 1
    return nxt

那么对于leetcode的第28道题来说完整的题解就应该是:

class Solution:
    def getNext(self, needle):
        nxt = [0]
        x = 1
        now = 0
        while x < len(needle):
            if needle[x] == needle[now]:
                nxt.append(now + 1)
                x += 1
                now += 1
            elif now:
                now = nxt[now - 1]
            else:
                nxt.append(0)
                x += 1
        return nxt

    def strStr(self, haystack: str, needle: str) -> int:
        if not needle:
            return 0
        nxt = self.getNext(needle)
        i = 0
        j = 0
        while i < len(haystack) and j < len(needle):
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            elif j:
                j = nxt[j - 1]
            else:
                i += 1
        if j == len(needle):
            return i - j
        else:
            return -1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值