KMP算法(Python)

KMP算法(Python)

    • 前言
    • KMP算法与BF算法的不同
    • next[]数组
    • 求next[]数组的值
    • KMP比较
    • 代码自取
    • 运行结果

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

前言

KMP算法是由KnuthMorrisPratt同时设计实现的,因此简称KMP算法。字符串匹配是计算机频繁进行的非常频繁的算法。其中比较经典的算法就是BF算法KMP算法,网上对于这两种算法讲解的也比较多,BF算法比较好理解,所以在这里就不再赘述。我们来简单的描述一下KMP算法以及代码实现(基于Python)。

KMP算法与BF算法的不同

这两种算法都是用模式串(p)去匹配主串(s)。在BF算法,每次匹配失败的时候,都要回溯到主串下一个字符继续和模式串开头比较,在模式串比较长的时候,这种算法的效率就比较低。
KMP算法的改进在于引进了next[]数组,在匹配过程中产生“失配”时,主串不用回溯,而模式串则退回next[]数组所指示的位置。
KMP算法(Python)_第1张图片

next[]数组

数据结构教材中,next[]数组的公式如下:
KMP算法(Python)_第2张图片
这个公式看起来就让人头大,直接劝退了很多人。在这里我用我的话描述一遍:
next[j]=t 代表在模式串第j个字符在与主串匹配失败时,模式串用过退回到第t个字符。
对于模式串P:abaabcac
next[1]=0 第1个字符和主串匹配失败时,因为前面根本没有元素,所以不用退,规定任何情况下,next[1]=0。
next[2]=1 第2个字符和主串匹配失败时,退回第1个字符
next[6]=3 第6个字符和主串匹配失败时,退回到第3个字符

求next[]数组的值

拿next[6]=3举例:
当第六个字符失配时,我们把前面的字符看成一个数组。
temp[5]="abaab"
这个数组中我们规定下标从1开始,明显的t1t2=t4t5。公式中k-1=2,所以k=3
即next[6]=3。
下面是代码实现:

def Get_next(p,next):             #求模式串p的next数组的值
    nums=len(p)                   #模式串中的元素个数
    for m in range(1,nums):       #从第1号元素开始算next数组值,第0号元素next数组的值默认是0
        k = 1
        for i in range(0,m):

            if i+1>=m-i:        #当左边的下标大于右边的下标则跳出循环
                break
            if p[0:i+1]==p[m-i-1:m]:
                k=i+2
        next.append(k)

KMP比较

我们只需在BF算法基础上改动,在失配时模式串退回到next[]数组指示位置。
实现代码如下:

def kmp_match(s,p,next):
    nums1=len(s)         #模式串中元素的个数
    nums2=len(p)
    i=j=0
    while i!=nums1 and j!=nums2:

        if c[i]!=p[j]:
            j=next[j]
            i+=1
        else :
            i+=1
            j+=1
    if j!=nums2 :
        print("匹配失败,主串中不包含模式串")
        return -1
    else:
        print(f"匹配成功,在主串中第{i-nums2+1}到第{i}")
        return 0

代码自取

def Get_next(p,next):             #求模式串p的next数组的值
    nums=len(p)                   #模式串中的元素个数
    for m in range(1,nums):       #从第1号元素开始算next数组值,第0号元素next数组的值默认是0
        k = 1
        for i in range(0,m):

            if i+1>=m-i:        #当左边的下标大于右边的下标则跳出循环
                break
            if p[0:i+1]==p[m-i-1:m]:
                k=i+2
        next.append(k)

def kmp_match(s,p,next):
    nums1=len(s)         #模式串中元素的个数
    nums2=len(p)
    i=j=0
    while i!=nums1 and j!=nums2:

        if s[i]!=p[j]:
            j=next[j]
            i+=1
        else :
            i+=1
            j+=1
    if j!=nums2 :
        print("匹配失败,主串中不包含模式串")
        return -1
    else:
        print(f"匹配成功,在主串中第{i-nums2+1}到第{i}")
        return 0

s=input("请输入主串")                  #主串
p=input("请输入模式串")                #模式串
p=list(p)
s=list(s)
next=[0]
Get_next(p, next)
kmp_match(s,p,next)

运行结果

在这里插入图片描述
在这里插入图片描述
KMP算法(Python)_第3张图片

制作不易,点个赞再走吧。

你可能感兴趣的:(Python,python,算法,字符串,数据结构)