KMP算法

问题定义:给定字符串string: abcdeabcea  以及匹配字符串parttern:  abce 问 parttern是否为string的子串,如果是请返回第一次出现索引的位置,否则返回-1

以下是暴力匹配的代码:

class Solution:
    def match(self, string,parttern):
        len1,len2 = len(string),len(parttern)
        i,j = 0,0
        while i<len1 and j<len2:
            if string[i]==string[j]:
                i+=1
                j+=1
            else:
                i=i-j+1
                j=0
        if j==len2:
            return i-j
        else:
            return -1

KMP算法:

暴力匹配算法是当string和parttern不匹配时,返回到string的下一个字符依次重新开始匹配。

而KMP算法遇到string和parttern不匹配时,partttern向右移动。从而节约了时间。

以下是KMP的代码:

 1 class Solution:
 2     def KMPmatch(self, string,parttern):
 3         len1,len2 = len(string),len(parttern)
 4         i,j = 0,0
 5         while i<len1 and j<len2:
 6             if j==-1 or string[i]==parttern[j]:
 7                 i+=1
 8                 j+=1
 9             else:
10                 j = nextp[j]
11         if j==len2:
12             return i-j
13         else:
14             return -1

KMP算法的描述:

1: 当  j == -1 或者 匹配成功时 ,继续匹配

2: 当 j!= -1 且不匹配时 i 不变, j = nextp[j]  (也就是 parttern向右移动了 j- next[p]个位置)

下面介绍 nextp

模式串parttern  为  abab

模式串 a b a b
最大前缀后缀公共元素长度 0 0 1 2

ab的前缀为 a ,后缀为b   因此表格1,2为0

aba的前缀为 a,ab 后缀为 ba,a  公共元素为a 因此表格为1 

abab的前缀为  a , ab , aba , 后缀为 bab, ab,b   公共元素ab  因此表格为2

nextp 即

 模式串

 a  b  a  b
 nexp  -1  0  0  1

 

nextp数组就是将表格1中的最大前缀后缀公共元素长度的初值设为-1, 然后整体右移.

nextp和最大长度表是等价的

我们计算parttern向右移动的长度时.

如果是用的最大长度表,  就是   j-当前不匹配元素的上一个元素在最大长度表中的值, 即 j-common[j-1]

如果用的是nextp表,就是 j - next[j]

构造数组nextp

nextp通过递归的方式求得. 假设我们已经知道 nextp[j]的值为k, 那么nextp[j+1]的值为:

如果  parttern[j] == parttern[k]  则 nextp[j+1] = next[j] + 1 = k+1

如果 parttern[j] != parttern[k]  则 迭代 k = next[k]判断 parttern[k] ?= parttern[j]  直到相等或者 next[k]=-1为止.

以下为整个代码部分.python

 1 class Solution:
 2     def getnext(self,parttern):
 3         nextp = [0]*len(parttern)
 4         nextp[0] = -1
 5         k,j = -1,0
 6         while j<len(parttern)-1:
 7             if k==-1 or parttern[j]==parttern[k]:
 8                 j+=1
 9                 k+=1
10                 nextp[j] = k
11             else:
12                 k = nextp[k]
13         return nextp
14 
15     def KMPmatch(self, string,parttern):
16         len1,len2 = len(string),len(parttern)
17         nextp = self.getnext(parttern)
18         i,j = 0,0
19         while i<len1 and j<len2:
20             if j==-1 or string[i]==parttern[j]:
21                 i+=1
22                 j+=1
23             else:
24                 j = nextp[j]
25         if j==len2:
26             return i-j
27         else:
28             return -1

 

posted @ 2020-09-01 21:54  扁鹊小脑  阅读(191)  评论(0)    收藏  举报