KMP算法利用next数组消除回溯思考
next数组的左右:消除回溯。即,在主串和模式串匹配的过程中,主串和模式串中有部分相同,相同的部分我们把它看做模式串的前缀串,如:
模式串(p): abcabcc
主串 (s): abcaddd
其中相同的部分肯定是模式串的子集。如上面例子中:abca为共同部分,abca为模式串abcab的子集。回溯的目的也就是共同部分和模式串本身的匹配的重合度,如上:p[4]和s[4]不匹配,很明显可以看出如果保持主串的匹配位置不变,即从s[4]开始不进行回溯,需要从模式串的p[0]开始。
最后归结为:取abcad对应模式串的abcab的p[4]的最后缀和模式串本身abcabccc的最前缀的最大匹配度,需要移动模式串最小的距离,从而消除回溯。
什么是最大匹配度和移动模式串最小的距离?
如:
模式串:aaaaaaacd
主串: aaaaaaafffff
其中f和c不匹配,主串不移动,模式串移动的最小距离:
aaaaaaacd
aaaaaaafffff
相对来说模式串只移动了一个单位的距离。aaaaaa为6是最大的匹配度(也可以3(aaa)、4(aaaa)等非最大匹配度)。最大匹配度是可以提前已知的匹配部分(公共部分为模式串的子集),不用再重复匹配。以此消除回溯。
在求取模式串的next数组时,为什么p[j] != p[k]时,k=next[k],
第一次:
主串:(要求得next[j-1] ,假设j=7)aaaaaac******
模式串:(模式串的前缀串) aaaaaaa (如果成功,k=7,最大前缀)
第二次:
主串:(要求得next[j-1] ,假设j=7)aaaaaac******
模式串:(模式串的前缀串) aaaaaaa(如果成功,k=6,小于最大前缀前5个肯定匹配)
第三次:
aaaaaac******
aaaaaaa (如果成功,k=5)
。。。。。。。。。
第六次:
aaaaaac******
aaaaaaa
第七次:
k=-1, j++;k++; next[j] = k;
方法getNext(String smallString):
while(j < smallString.length() -1){
if(k == -1 || smallString.substring(j,j+1).equals(smallString.substring(k,k+1))){
j++;
k++;
next[j] = k;
}else{
System.out.println("j: " + j + " ,k: " + k + ", next[k]: " + next[k]);
k = next[k];
}
}