土味KMP
本文是我对KMP的一点理解,KMP是用于字符串匹配的一种算法,而KMP的精髓就在于求解NEXT数组(即跳表),别的都是一看就懂,而NEXT数组使用时最关键的一句代码就是K=NEXT[K],理解了这个,KMP基本就懂了。(我的建议是自己画一遍KMP的匹配流程,这样很容易就懂了)
我比较喜欢简洁的东西,网上那种介绍KMP的博客不知道为啥篇幅很长,我直接没有看的欲望。这里还是先说下KMP设计的定义,模式串:你想要查找的字符串,文本串:给定的文本串,举个例子,你想要在字符串“abcdabd”中查询字符串"dab"的位置,那“abcdabd”就是文本串,“dab"就是模式串,然后next数组的值是什么意思呢,next[i]就代表模式串中前i个字符的最长匹配前缀后缀长度,还是举个例子,比如模式串是"abcdabd”,那么有7个字符,next数组的长度也是7,next[0]一直到next[6],那么next[6]=2,因为在能匹配的前缀和后缀中,“ab"最长,长度为2,注意:前缀不能是字符串本身,即"abcdab"的最长的前缀为"abcda”,为什么呢,大家是这么规定的,可能比较方便。顺带提一下,根据next数组的定义,next[0]=-1(这也是约定俗成),next[1]=0。那么如何求解next数组呢,下面是我的代码,个人感觉是比较贴合定义的,很好理解。
(ps:之前贴上来的代码格式没弄好,写的也有问题,这里重新编辑一下)
public static void main(String[] args) {
System.out.println(kmp("ababcabcacbab","bcabc"));
}
public static int kmp(String s,String moshistr){
//next数组只需要这么长的原因是:判定最后一个字符时只需要用到next[moshistr.length-1],所以next数组长度这样定义
int[] next = new int[moshistr.length()];
getnext(moshistr,next);
int j=0;
for (int i=0;i<s.length();i++){
//跳出该while循环表示要么i,j匹配成功,要么j==-1(说明一直整个模式串都和i所对应的字符不匹配)
while ((j!=-1)&&s.charAt(i)!=moshistr.charAt(j)){
j=next[j];
}
j++;
//返回模式串在查询串匹配时的起始下标
if (j==moshistr.length()){
return i-j+1;
}
}
return -1;
}
//next[i]代表模式串s中前i个字符的next值(即前i个字符的最长前缀后缀匹配)
//next长度为s.length()+1
//这里是直接用最长前缀后缀的定义求解next
public static void getnext(String s,int[] next){
next[0]=-1;//next[1]默认为0
for (int i=2;i<s.length();i++){
int j=next[i-1];
while (j!=-1&&s.charAt(i-1)!=s.charAt(j)){
j=next[j];
}
if (j==-1){
j++;
}
//如果匹配成功则赋值,否则默认值为0
if (s.charAt(i-1)==s.charAt(j)){
next[i]=++j;
}
}
System.out.println();
for (int x:next){
System.out.print(x+" ");
}
System.out.println();
}