KMP算法浅析
具体参见: KMP算法详解
背景:
KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。
KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。
在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。
对于next[]数组的定义如下:
1) next[j]=-1 j=0
2) next[j]=max k:0<k<j P[0...k-1]=P[j-k,j-1]
3) next[j]=0 其他
如:
P a b a b a
j 0 1 2 3 4
next -1 0 0 1 2
即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]
next的求解程序如下:
1 private int[] next(String str){ 2 if(str == null || str.length() == 0){ 3 return null ; 4 } 5 int [] next = new int [str.length()] ; 6 next[0] = -1 ; 7 int lastSame = 0 ; 8 for(int i = 1 ; i < str.length() ; i++ ){ 9 char temp = str.charAt(i) ; 10 next[i] = lastSame ; 11 if(temp == str.charAt(lastSame)){ 12 lastSame++ ; 13 }else{ 14 lastSame = 0 ; 15 } 16 } 17 18 return next ; 19 }
通过next采用KMP算法判断是否匹配的代码如下:
1 /** 2 * 若src包含dest子串,则返回src中dest子串出现的位置(首字符的位置), 3 * 若不包含,则返回-1 4 * @param src 5 * @param dest 6 * @return 7 */ 8 private int KMPmatch(String src, String dest){ 9 if(src == null || dest == null || src.length() < dest.length()){ 10 return -1 ; 11 } 12 int [] next = next(dest); 13 int i = 0 ; 14 int j = 0 ; 15 while(i < src.length()){ 16 if((j == -1) || (src.charAt(i) == dest.charAt(j))){ 17 i++ ; 18 j++ ; 19 }else{ 20 j = next[j] ; 21 } 22 23 if(j == (dest.length())){ 24 return i-j ; 25 } 26 } 27 28 return -1 ; 29 }