字符串匹配算法,一种是朴素算法,即字符串S与匹配字符串P从0开始逐个匹配,失配后右移一位从新匹配。
另一种更高效的算法即是KMP算法。
例如:S[0,n],P[0 ,m]
如果S[ i ] != P[ j ]; 此时必有 式A:S[ i-j, i-1 ] = P[ 0 , j-1 ] , 如果使用朴素算法则从S[ i-j+1] 开始与 P重新逐个匹配(即比较S[ i-j+1 ,i-j+1+m] 、P[0, m ]),这样时间复杂度为O(n*m),效率低。
若我们保持S索引不变(即先考虑索引 i 之前的部分)上述比较等价于 式B:S[ i-j+1 , i-1] =? P[ 0, j-2 ];式B对于式A来看,假如我们将S看成不动,则P相对S右移了一位。
在此假设 P右移K位,
1)、有 式C S[ i-j+k , i-1] = P[ 0 , j-k-1] ( 0<k<=j-1);同时由式A 得 式D S[ i-j+k , i-1] = P[ k, j-1 ] (k < =j-1), A中 j-1位相等,后k位也相等;
由 C 、D 可得 E:P[0 , j-k-1] = P[ k , j-1] ;故可得 P[ 0 , j-1] 子串的前缀=后缀。(前面j-k 个等于 后面 j-k个)
令 next = j-k;由上述可得其只与P[ 0 ,j-i] 有关,而与S无关;
故假如我们求出各P[ 0, j ] ( 0<=j <=m)对应的 next值,即我们需要得到一个Next[m+1] 数组保存对应的next值;则当在任意位置失配时我们可以得到对应的右移值 k = j-next;
2)、否则比较 S[ i ] 、P[ 0 ];
Next数组的求法:
假设 next[ j ] = t ==> P[ 0 , t-1]= P[ j-t+1 ,j] ------ F;
如果 P[ t ] = P[ j+1 ] ==> next[ j+1] = t +1 = next[ j ] +1 -------G;
如果 P[ t ] != P[ j+1 ] ,此时不能通过 next[ j ] 推导 next[ j+1 ],需要另行计算;
//假如P[ 0 , v-1] = P[ j-v+1 , j ] ( v < t)------------I;
//由 I、F得 P[ 0 , v-1] = P[ t-v , t-1] ( 因为 I中的两项分别为F中两项的子集) == 》 next[t-1] = v ---------------J
//若P[ v ] = P[ j+1] 则 next[ j+1 ] = v + 1 = next[t-1] +1 ,否则继续循环。
换一种说法:
因next[ t ] = v (t <j , 故已经求得 ),则 P[ 0 , v-1] = P[ t-v+1 , t] = P[ j-v+1 , j]
如果 P[ v ] = P[ j+1] 则 next[ j+1 ] = v + 1 否则继续循环
next 实例算法:
public static int[] getNext(char[] p) { if(p == null || p.length == 0)return null; int len = p.length; int i = 0 , j=-1; int[] next = new int[len]; next[i] = -1; while(i<len-1) { if(j== -1 || p[i] == p[j]) { ++i; ++j; if(p[i] != p[j]) {//因为p[i] != p[next[i]](如果相等,移动后p[next[i]] == p[i] == s[index] 和原来一样失配) next[i] = j; } else {//猜测如果 next[i] = next[j]; } } else {//如果不相等,需要在前j个字符中获取最长的前缀=后缀的子串 j = next[j];//新的j值,表示p[0,j) ==p[i-j,i) } SortHelper.showArray(next); } return next; }
kmp 算法
public static int kmpSearch(char[] s , char[] p) { if(s== null || p== null) { return -1; } int sLen = s.length; int pLen = p.length; if(sLen <pLen) { return -1; } int[] next = getNext(p); int j=0; for(int i=0 ; i<sLen ;) { if(s[i] == p[j]) { if(j== pLen -1) { return i-j; } i++; j++; } else { j = next[j]; if(j==-1) { i++; j++; } } } return -1; }
参考链接:
http://blog.csdn.net/v_july_v/article/details/7041827