KMP字符串比对算法理解

KMP算法

一种字符串比对算法,寻找存在于长字符串中的子串,由Knuth、Morris、Pratt三个同时提出来。

算法的基本思路是:

假设有序列seq(长度为m)和子序列subseq(长度为n),
首先遍历序列seq,找到subseq[0]第一次出现在seq中的位置k;

然后顺次比较subseq[j](0 和以seq[i-1]结尾长度为j的序列seq[i-j,i](此处之所以选择用i而不是k来描述seq的片段,是想通过序列片段
而不是单个字符进行移动,继而减少移动次数):

若在j==n-1时,每个元素都相等,则定位了一个子序列,重复上面的过程即可找到所有子序列的分布位置,

若对某一特定的j(0 seq[i], 这时则宣告最初找到的k不合意(应该后移),无法继续
延伸,这时需要调整j的值, 继而影响到k的值。为了调整后,依然满足subseq[0,j'] == subseq[i-j',i],就
要求j'应该满足subseq[0,j']==subseq[j-j',j],同时最佳j'应该是满足这个条件的最大值且j' <> j, 使
得能继续参与匹配的序列最长。当然也存在不能找到合适的j'的情况,这时另j'等于0, 而增加i的值直到再次碰到
subseq[0]。同时,我们可以看到j'的取值只取决于subseq,因此我们可以提前构建出这样一个索引数组来指导错误匹配之后的移动。

索引数组index的构建:
索引数组的构建就是对字符串进行自我扫描的过程,每个值都可以递归的由其前一个位的值得出。
假设index[j-1] = k, 只要index[k] == index[j],index[j] = index[j-1]+1, 因为index[0,k] = index[j-k,j], 所以index[0,k+1] == index[j-k, j+1]。若index[k] != index[j],这时可以回溯到index[index[j-1],若依然不满足则递归index[index[index[j-1]],直到满足或取值为0, 由此得到index数组。


假设seq = 'abaebacddebacdbace', subseq = 'bace'.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
a b a e b a c d d e b  a  c  d  b  a  c  e

b a c e
0 1 2 3

当k=1时,subseq[0] == seq[k],
然后subseq[1] == seq[2], subseq[2] != seq[3], 这时需要调整j的值,使得subseq[0,j']依然等同于
seq[i-j'+1,i], 这就使得j'要满足使得subseq[0,j]的前j'的字母和后j'个字母完全相同, 由于没有合适的,
j'取值0,此时继续增大i的值直到再次在seq里遇到subseq[0], 重复以上过程。这个例子比较特殊没有利用到算法的优势。
若子序列不存在重复,用KMP算法和用下面的一个bruteforce程序效果应该相差不大, 另外python的find和index在处理字符串时速度也很可观。


另一个例子是matrix67上的, 大家可过去参考下。

参考:http://www.matrix67.com/blog/archives/115

http://stackoverflow.com/questions/425604/best-way-to-determine-if-a-sequence-is-in-another-sequence-in-python

 

--------------------------- Bruteforce mathod: --------------------------- def index(subseq, seq): ''' index(subseq, seq) -->a list of numbers or -1 Return an index of [subseq] in the [seq]. Or -1 if [subseq] is not a subsequence of [seq]. The time complexity of the algorithm is O(n*m), where n, m = len(seq), len(subseq). >>>index('12', '0112') [2] >>>index([1,2], [011212]) [2, 4] >>>index('13', '0112') -1 ''' i, n, m = -1, len(seq), len(subseq) index = [] try: while True: i = seq.index(subseq[0], i+1, n - m + 1) if subseq == seq[i:i+m]: index.append(i) except ValueError: return index if len(index) > 0 else -1 def subseqInSeq(subseq, seq): ''' subseqInSeq(subseq, seq) ---> list or -1 The same as index. ''' indexList = [] m = len(subseq) subseqRepla = '*' * m while subseq[0] in seq: index = seq.index(subseq[0]) if subseq == seq[index:index+m]: indexList.append(index) seq = seq.replace(subseq, subseqRepla, 1) else: seq = seq.replace(subseq[0], '*', 1) return (indexList if len(indexList) > 0 else -1) def main(): print index('ab', 'abcdab') print subseqInSeq('ab', 'abcdab') ------------------------------------------------------------ KMP def compute_prefix_function(p): m = len(p) pi = [0] * m k = 0 for q in range(1, m): while k > 0 and p[k] != p[q]: k = pi[k - 1] if p[k] == p[q]: k = k + 1 pi[q] = k return pi def kmp_matcher(t, p): n = len(t) m = len(p) pi = compute_prefix_function(p) q = 0 for i in range(n): while q > 0 and p[q] != t[i]: q = pi[q - 1] if p[q] == t[i]: q = q + 1 if q == m: return i - m + 1 return -1

你可能感兴趣的:(算法,算法,function,algorithm,numbers,matrix,list)