KMP算法是一个高效的串匹配算法,常被人戏称为‘看毛片算法’,其解决的问题为:
给定两个字符串:
t = 'adjfdajfidjfiasidjfosdsfossssfdsd'
p = 'jfidjf'
判定t中是否包含p
首先,我们来看一个朴素的串匹配算法
#coding:utf-8 ''' 朴素的串匹配法 ''' def naive_matching(t,p): m, n = len(p), len(t) i, j = 0, 0 while i < m and j < n: if p[i] == t[j]: i, j = i + 1, j + 1 else: #字符不同,则考虑下一个位置 i, j = 0, j-i+1 if i == m: #i==m表示找到匹配,则返回下标。 return j-i return -1 #无匹配时,返回特殊值
KMP算法
#coding:utf-8 ''' KMP看毛片算法: 1、朴素的匹配算法,其时间复杂度为O(n*m),KMP的时间复杂度为O(n+m) 2、其基本思想为匹配中不回溯,关键点在于匹配失败时模式串如何前移。 3、核心点在于定义一个长度为m的转移函数pnext,其含义为一个固定的字符串的最长前缀和最长后缀。 4、关于最长前缀和最长后缀: 比如:abcsksabc,那么这个数组的最长前缀和最长后缀相同必然是abc。 cbcbc,最长前缀和最长后缀相同是cbc。 abcbc,最长前缀和最长后缀相同是不存在的。 **注意最长前缀:是说以第一个字符开始,但是不包含最后一个字符。 比如aaaa相同的最长前缀和最长后缀是aaa。** 对于目标字符串ptr,ababaca,长度是7,所以 pnext[0],pnext[1],pnext[2],pnext[3],pnext[4],pnext[5],pnext[6]分别计算的是 a,ab,aba,abab,ababa,ababac,ababaca的相同的最长前缀和最长后缀的长度。 由于a,ab,aba,abab,ababa,ababac,ababaca的相同的最长前缀和最长后缀是 “”,“”,“a”,“ab”,“aba”,“”,“a”,所以next数组的值是[-1,-1,0,1,2,-1,0], 这里-1表示不存在,0表示存在长度为1,2表示存在长度为3。这是为了和代码相对应。 比如pnext中某个字符对应的值是4,则在该字符后的下一个字符不匹配时,可以直接移动往前移动ptr 5个长度,再次进行比较判别 ''' #开始构造pnext表函数 def gen_pnext(p): i, k, m = 0, -1, len(p) pnext = [-1]*m #初始数组全为-1 while i< m-1: #生成下一个pnext元素 if k== -1 or p[i] == p[k]: i, k = i+1, k+1 if p[i] == p[k]: pnext[i] = pnext[k] else: pnext[i] = k else: k = pnext[k] return pnext def matching_KMP(t, p, pnext): ''' 毛片算法主程序 ''' j, i = 0, 0 n, m = len(t), len(p) while j < n and i < m: if i == -1 or t[j] == p[i]: j, i = j+1, i+1 else: i = pnext[i] if i == m: return j-i return -1 #无匹配则返回特殊值