KMP算法的思路请参考:kmp思想
能理解KMP的思想和能理解KMP代码是两回事,很多时候我们理解了思想,却看不懂代码实现,本篇博客主要是记录代码实现KMP的思路。
KMP算法的代码实现中,最重要也是最难理解的,就是next数组,下面直接上图:
首先,先假设我们已知了next数组的next[j]=k,意思就是j位置之前,由k-1个相同前后缀
接下来,在已知的前提下,推导j+1的情况,如果j向前一位变成j+1,之前的k位置S[k]如果等于S[j],那么next[j+1]=k+1
注意:这里是S[k]等于S[j],不是next
如果不相等,那么k就回溯到k=next[k]的值,因为next[k]中记录了k位置前面的最长相同前后缀,如果S[k]和S[j]不相等,那么k位置只能再往前找,看看k位置前面的相同前缀是否可以等于S[j]。因为next数组的功能就是来找最长相同前后缀的,而S[j]是后缀,那么前缀加上S[k]不能和S[j]相同,那么只能往前面找前面已经相同的前缀中,有没有能和S[j]这个后缀相同的。
上面这句话是KMP代码的核心思想,能理解这句话就能理解KMP的代码。
如果可以,就让next[j+1]=k+1,此时k其实是前面的next[k],如果k=next[k]也不行,那么就继续让k=next[k]
一直到出现相等。或者k=1时,因为next[1]=0,表示到头了。
这就是next数组的代码思想,下面是在代码中的具体体现:
public static boolean kmp(String str,String s){
char[] T = str.toCharArray();
char[] S = s.toCharArray();
//定义next数组,next数组是根据短串生成的,别搞错了。
//因为索引0没用到,因此数组长度加1
int[] next=new int[s.length()+1];
//定义两个指针
int j=1;
//表示前面j-1位置的next数组的值
int k=0;
//定义next[1]=0,next[1]=0表示短串已经回溯到头了,此时应该移动长串
next[1]=0;
//生成next数组,生成next数组的思路在图中详细解释
while(j<s.length()){
if(k==0||S[j-1]==S[k-1]){
next[++j]=++k;
}else {
k=next[k];
}
}
int i=1;
int l=1;
while (i<=T.length&&l<=S.length){
//如果匹配成功,长串短串依次加1。
//如果匹配失败,短串用next数组回溯,如果回溯到next[1]=0时,l=0,此时表示短串回溯到头了,
//短串不能再回溯了,长串应该往后一位了(对应情况:如果第一位都不匹配,next[1]=0,长串应该后移一位)
if(l==0||T[i-1]==S[l-1]){
i++;
l++;
}else {
l=next[l];
}
}
//l>S.length说明上面的while循环是短串遍历完跳出来的,对应匹配成功的情况
if(l>S.length){
return true;
}else {
return false;
}
}