python之KMP算法(原理详解)

KMP算法其实就是字符串匹配的一种高效算法,通常称作模式匹配;
本文结构如下:
一、朴素的匹配算法
1、匹配的概念
2、朴素算法原理
3、代码实现
二、KMP算法
1、KMP算法简介
2、KMP算法原理详解
3、求出next()函数
4、代码示例
一、朴素的匹配算法
1、匹配的概念
如下图所示,就是模式串T与主串S匹配成功,模式串首尾间的各个元素与主串之间的某一段元素完全相同
python之KMP算法(原理详解)_第1张图片

2、朴素算法原理
将模式串中的元素与主串中的元素逐个匹配,如果失配,则模式串向右滑动一个元素,与主串继续进行匹配,如下图所示
python之KMP算法(原理详解)_第2张图片
3、代码实现

#定义朴素匹配的函数
#主串参数 s ,模式串参数 t
def simple_matching(s, t):
    s = list(s)
    t = list(t)
    m, n = len(s), len(t)
    i, j = 0, 0
    while i < m and j < n:
        if s[i] == t[j]:
            i += 1
            j += 1
        else:
            i = i - j + 1
            j = 0
    if j == n:
        return i - j
    return 0
s = 'ababcabcacbab'
t = 'abcac'
print(simple_matching(s, t))
>>>5

二、KMP算法

1、KMP算法的简介

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

关于上段解释,看了也基本等于没看,不明白在说什么,但其核心意思是以下几点:
1、利用匹配失败后的信息,进行下次匹配
2、通过next()函数实现

通俗的描述一下KMP算法。

首先,朴素算法是这样说的:
将模式串中的元素与主串中的元素逐个匹配,如果失配,则模式串向右滑动一个元素,与主串继续从 j = 0 进行匹配

KMP算法描述相近:
将模式串中的元素与主串中的元素逐个匹配,如果失配发生在主串 元素S[ i ]与模式串元素 T[ j ] 上,那么模式串 t 向右滑动尽可能多的元素个数后,模式串 T[k] 与主串 S[ i ] 继续匹配

KMP算法的核心与重点就是通过next()函数求出 k 值,这样就不用向朴素算法那样每次只滑动一个元素,然后又从 j = 0开始匹配。

2、KMP算法原理详解

上面对于KMP算法的文字解说,不直观,也不容易理解,下面用图对KMP原理进行说明;
python之KMP算法(原理详解)_第3张图片

由上可知此时求出k值就是该算法的核心问题,k值就是通过next()函数求解出来的,不同的 j 对应对应不同的k值;
即可以得出next[j]函数的定义:
python之KMP算法(原理详解)_第4张图片
对于next[j]的各种取值方式,说明如下:
python之KMP算法(原理详解)_第5张图片
此时举例的处next[j]的值
python之KMP算法(原理详解)_第6张图片

3、求出next()函数
由以上可知next()函数的求解是KMP算法的核心内容。
下面讲解如何求出next(j)函数
python之KMP算法(原理详解)_第7张图片

关于next[j]函数值,就有上面的方法求得

4、代码示例

#定义next_kmp()函数,求出next[j]的值
t = "abaabcac"
def next_kmp(t):
    t = list(t)
    j, k ,n = 0, -1, len(t)
    pnext = [-1] * n
    while j < n-1:
        # k == -1的意义就是说此时的k值不存在
        # 当k不存在时,此时的pnext[j] = 0
        if k == -1 or t[j] == t[k]:
            j, k = j+1, k+1
            pnext[j] = k
        else:
            k = pnext[k]
    return pnext
print(next_kmp(t))
"""[-1, 0, 0, 1, 1, 2, 0, 1]"""
s ='ababcabcacbab'
t ='abcac'
#pnext列表作为求得的next(j)函数
#s为主串,t为模式串
def matching_kmp(s,t,pnext):
    s = list(s)
    t = list(t)
    i, j = 0, 0
    m, n = len(s), len(t)
    while j < n and i < m:
        if j == -1 or s[i] == t[j]:
            i, j = i+1, j+1
        else:
            j = pnext[j]
    if j == n:
        return i - j
    return -1

print(matching_kmp(s,t,pnext = next_kmp(t)))
"""5"""

以上就是KMP算法的代码

总结:
朴素算法的时间复杂度O(n*m),但在实际情况中接近O(n+m),而只有当模式串部分匹配较多的情况下,KMP算法才会更为高效!

你可能感兴趣的:(python之KMP算法(原理详解))