字符串匹配算法KMP
看了阮一峰的博客,然后找到了 关于KMP 算法相当详细的博客: https://blog.csdn.net/v_july_v/article/details/7041827
摘录:
- 如果模式串中存在相同前缀和后缀,即pj-k pj-k+1, ..., pj-1 = p0 p1, ..., pk-1,那么在pj跟si失配后,让模式串的前缀p0 p1...pk-1对应着文本串si-k si-k+1...si-1,而后让pk跟si继续匹配。
- 之前本应是pj跟si匹配,结果失配了,失配后,令pk跟si匹配,相当于j 变成了k,模式串向右移动j - k位。
- 因为k 的值是可变的,所以我们用next[j]表示j处字符失配后,下一次匹配模式串应该跳到的位置。换言之,失配前是j,pj跟si失配时,用p[ next[j] ]继续跟si匹配,相当于j变成了next[j],所以,j = next[j],等价于把模式串向右移动j - next [j] 位。
- 而next[j]应该等于多少呢?next[j]的值由j 之前的模式串子串中有多大长度的相同前缀后缀所决定,如果j 之前的模式串子串中(不含j)有最大长度为k的相同前缀后缀,那么next [j] = k。
写了python的实现,记录一下:
1 #!/usr/bin/env python 2 #-*- coding: utf-8 -*- 3 4 import array 5 6 7 def bruteForce(text, p): 8 out = [] 9 textLen = len(text) 10 pLen = len(p) 11 12 i = 0 13 j = 0 14 15 while(i < textLen): 16 if text[i] == p[j]: 17 i += 1 18 j += 1 19 else: 20 print('i:%d\tj:%d' % (i,j)) 21 i = i - j + 1 22 j = 0 23 24 if j == pLen: 25 out.append(i - pLen) 26 j = 0 27 else: 28 continue 29 return out 30 31 #优化前next 32 def getNext(p): 33 pLen = len(p) 34 next = [ -1 for x in xrange(pLen)] 35 36 k = -1 37 j = 0 38 39 no = 0 40 41 while(j < pLen -1): 42 no += 1 43 print( 'NO.= %d, k= %d, j= %d' % (no, k, j) ) 44 #p[k]表示前缀,p[j]表示后缀 45 if k == -1 or p[k] == p[j]: 46 k += 1 47 j += 1 48 next[j] = k 49 else: 50 k = next[k] 51 return next 52 53 #优化后next 54 def getNext2(p): 55 pLen = len(p) 56 next = [ -1 for x in xrange(pLen)] 57 58 k = -1 59 j = 0 60 61 no = 0 62 63 while(j < pLen -1): 64 no += 1 65 print( 'NO.= %d, k= %d, j= %d' % (no, k, j) ) 66 #p[k]表示前缀,p[j]表示后缀 67 if k == -1 or p[k] == p[j]: 68 k += 1 69 j += 1 70 if p[k] != p[j]: 71 next[j] = k 72 else: 73 #因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]] 74 next[j] = next[k] 75 else: 76 k = next[k] 77 return next 78 79 80 def kmp(text, p, next): 81 out = [] 82 textLen = len(text) 83 pLen = len(p) 84 85 i = 0 86 j = 0 87 88 while(i < textLen): 89 #①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++ 90 if j == -1 or text[i] == p[j]: 91 i += 1 92 j += 1 93 else: 94 #②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j] 95 #next[j]即为j所对应的next值 96 j = next[j] 97 98 if j == pLen: 99 out.append(i - pLen) 100 j = 0 101 else: 102 continue 103 104 return out 105 106 107 if __name__ == '__main__': 108 109 text = 'asdfabdewdadsabacababc' 110 p = 'ababc' 111 112 textCharArray = array.array("B",text.strip()) 113 pCharArray = array.array("B", p.strip()) 114 115 print(textCharArray) 116 print(pCharArray) 117 118 #暴力匹配 119 #print(bruteForce(textCharArray, pCharArray)) 120 121 #kmp 122 #get next array 123 next = getNext2(pCharArray) 124 print(kmp(textCharArray, pCharArray, next))