KMP算法

一、背景

给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题。
Knuth-Morris-Pratt 算法(简称 KMP,网上有人戏称“看毛片”,我的输入法打出来的首位竟然是“烤馍片”)是解决这一问题的常用算法之一,这个算法是由高德纳(Donald Ervin Knuth)和沃恩·普拉特在 1974 年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终三人于 1977 年联合发表。

二、暴力匹配(朴素字符串匹配算法)

看到这样的问题,对我这个菜鸟来说,第一反应当然就是暴力匹配,代码如下:

    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        start = 0
        if needle == '':
            return (start)
        while True:
            if start + len(needle) > len(haystack):
                return (-1)
            else:
                if haystack[start:start + len(needle)] == needle:
                    return (start)
                else:
                    start += 1

暴力匹配的时间复杂度为 O(nm),其中n为 S 的长度,m为 P 的长度。很明显,肯定还有更优的匹配方法

三、KMP字符串匹配算法

这里,我在网上搜了一下,看了几篇,大部分一开始看下来是真的有点懵逼,其中有一篇,至少我看下来是看懂了,虽然把这篇文章收藏了,但是担心万一哪一天要收费或者文章没了(之前还真发生过),所以自己还是截图贴在博客里,随时可以看看回顾(当然在这篇文章最后,我会附上原文链接)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这儿我就放上自己的Python代码:

#未优化的next数组
def GetNext(P, NEXT):
    p_len = len(P)
    i = 0 
    j = -1  
    next.append(-1)

    while (i < p_len-1):
        #print (P[i] + 'and' + P[j])
        if (j == -1 or P[i] == P[j]):
             
            i += 1
            j += 1
            next.append(j)
        else:
            j = next[j]

P = "ABCDABCE"
next = []
GetNext(P,next)
print (next)

个人还是比较赞同网上很多作者的说法,即next数组的确是KMP的核心。j=next[i]这个更是让我直接跪了,核心中的灵魂;用网上一篇内容说的:初学者能一眼看明白j=next[i]这一步的,请允许我尊称一声“大神”

四、KMP优化

在这里插入图片描述
其实简单点说,就是在"i=4"的时候,要考虑一下这个第二个“A”后面的字符和第一个“A”后面的字符是否相等,如果相等,那next[5]的值为“0”,如果不相等,则为“1”;代码如下:

#优化后的next数组
def GetNext(P, NEXT):
    p_len = len(P)
    i = 0 
    j = -1  
    next.append(-1)

    while (i < p_len-1):
        #print (P[i] + 'and' + P[j])
        if (j == -1 or P[i] == P[j]):
             
            i += 1
            j += 1
            if P[i] != P[j]:
                next.append(j)
            else:
                next.append(next[j])
        else:
            j = next[j]
            #print (j)

P = "ABCDABCE"
next = []
GetNext(P,next)
print (next)

五、完整代码

#! /usr/bin/python
# -*- coding:utf-8 -*-

'''
#未优化next数组
def GetNext(P, NEXT):
    p_len = len(P)
    i = 0 
    j = -1  
    next.append(-1)

    while (i < p_len-1):
        #print (P[i] + 'and' + P[j])
        if (j == -1 or P[i] == P[j]):
             
            i += 1
            j += 1
            next.append(j)
        else:
            j = next[j]

P = "ABCDABCE"
next = []
GetNext(P,next)
print (next)
'''
#优化后next数组
def GetNext(P, NEXT):
    p_len = len(P)
    i = 0 
    j = -1  
    next.append(-1)

    while (i < p_len-1):
        #print (P[i] + 'and' + P[j])
        if (j == -1 or P[i] == P[j]):
             
            i += 1
            j += 1
            if P[i] != P[j]:
                next.append(j)
            else:
                next.append(next[j])
        else:
            j = next[j]
            #print (j)

P = "ABCDABCE"
next = []
GetNext(P,next)
print (next)

def KMP(S, P):
    i = 0
    j = 0
    s_len = len(S)
    p_len = len(P)
    while (i < s_len and j < p_len):
        if (j == -1 or S[i] == P[j]):
            i += 1
            j += 1
        else:
            j = next[j]
    if j == p_len:
        #print (i-j)
        return (i-j)

    return (-1)

S = "ABDEABCDABCE"
KMP(S,P)

参考文章链接:KMP算法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值