在我看来阮一峰的字符串匹配的KMP算法 对于入门挺好,但是对于KMP的实现很不友好,被绕进去了很多次.
始终觉得<算法导论>里面的方法更加简洁一点,虽然需要自己花点时间演算一下才能理解.
#计算next数组
def compute_prefix(p):
m = len(p)
res = [-1 for _ in range(m)]#置-1作为没有找到匹配前缀的标志
res[0] = -1
k = -1
for q in range(1,m):
while k > -1 and p[k+1]!=p[q]:
k = res[k]#若失位,在已匹配到的信息中找.(若得到-1,会跳出循环)
if p[k+1] == p[q]:
k = k + 1
res[q] = k
return res
#KMP匹配过程
def kmp_matcher(t,p):
n, m = len(t), len(p)
nxt = compute_prefix(p)#得到next数组
q = -1
for i in range(n):
#若失位的操作
while q > -1 and p[q+1] != t[i]:
q = nxt[q]
#从失位恢复处或p最左端继续匹配
if p[q+1] == t[i]:
q = q + 1
#当p字符串的下标q达到m-1时,意味着匹配成功,找到一个目标pattern
if q == (m - 1):
#输出pattern起始位置
print("Pattern occurs with shift ",i-m+1)
#继续在t中寻找下一个pattern
q = nxt[q]
#测试
p = "ababababca"
# t中藏了两个ababababca
t = "vhjvgdhacvjchacvajcbcababababcahvcdakcacbcbajhcacvacgacahcjachascababababca"
kmp_matcher(t,p)
Pattern occurs with shift 21
Pattern occurs with shift 65
在电话面试里遇到了KMP算法, 算是之前看过也了解过, 但是没有仔细去真正实现过,或许KMP本身不太适合作为电话面试的题目,也或许是自己的表达能力还未到水平,脑里对KMP的概念难以用语言表达出(最长公共前后缀? 实现O(m+n)? next数组? 似乎几个关键词都难以表达对KMP的理解)
网上对KMP的现实有很多,但是在我看来,在计算next数组的部分应该要达到O(m)级别的,看了一下很多人的做法都是用python set集合或者遍历以一个O(m*m)作为解决方案,是不够准确的. 对于KMP的细究还是有必要的, 如果不细究早就用朴素匹配解决了, 哪里还用得着设计一个KMP.
另一个要点是入门一个算法,第一步是抽象想象,能以一个动画想象算法过程.第二步是以一个实例用纸笔演算一次. 加上最后的实现,基本可以掌握一个算法的70%了.
附上一张截图帮助理解next数组的计算.