什么是KMP?
主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
主要用于文本的匹配。里面有个重要的概念叫做前缀表,根据我的理解前缀表里面融合了动态规划的的思想,下面的的代码中也可以看出来。
前缀表
前置表即公共最长字串的长度,是长度不是个数,这里可以清晰的算法每个的前缀表。
代码实现如下:
def prefix_function(s):
n = len(s)
pi = [0] * n
j = 0
for i in range(1, n):
a = s[i]
b=s[j]
while j > 0 and s[i] != s[j]: # 当前位置s[i]与s[j]不等
j = pi[j - 1] # j指向之前位置,s[i]与s[j]继续比较
if s[i] == s[j]: # s[i]与s[j]相等,j+1,指向后一位
j += 1
pi[i] = j
return pi
相当于一直找重复的值,运用动态规划思想,不需要重复遍历。即可实现next列表的实现,这个;列表主要功能就是存储公共最大字串。
接下来就是运用这个next来匹配。
字符串匹配
逐渐的遍历,往回退看i=2的时候j等于几和它匹配,如果有则指向最长公共字串的地方,假如没有i则继续遍历。
代码如下:
def strStr(s: str, t: str):
def prefix_function(s):
n = len(s)
pi = [0] * n
j = 0
for i in range(1, n):
a = s[i]
b=s[j]
while j > 0 and s[i] != s[j]: # 当前位置s[i]与s[j]不等
j = pi[j - 1] # j指向之前位置,s[i]与s[j]继续比较
if s[i] == s[j]: # s[i]与s[j]相等,j+1,指向后一位
j += 1
pi[i] = j
return pi
n, m = len(s), len(t)
pi = prefix_function(t) # 预处理得到t的前缀函数
'''再次基于KMP的思想在s中匹配t'''
j = 0
for i in range(n):
while j>0 and s[i] != t[j]:
j = pi[j-1]
if s[i] == t[j]:
j += 1
if j == m: # 匹配到了t,直接返回
return s[i-m+1:i+1]
return -1
总结
大家需要自己体会KMP的精妙的思想,经常复习。