KMP,即The Knuth-Morris-Pratt Algorithm,中间的单词是创造早这个算法的三个人,该算法可以用于字符串的匹配查找,该算法的优势体现在当主串和模式串有重复字符时,可以降低时间复杂度。一般在学习算法之前所用的方法的方法都是暴力求解(Brute Force,BF),下面我将一一讲解这两种算法。
一.BF
先不说介绍,先看查找过程,如下图:
这边p从M的第一位开始比较,第一位满足,接着进行第一位......五位的比较,发现第六的时候并不满足,这时,开始M的第二位与P的第一位开始比较,如图:
发现M[1]与P[0]并匹配,于是M的下标开始移动。。。。就这样一直遍历,直到在M中找到了连续的与P长度相等并相匹配的字符串。
2.KMP
2.1 NEXT数组
KMP我觉得最关键的是求得它的next的数组,所谓next数组,next[i]表示i位之前的字符前缀与后缀最大的匹配数,以abiabc,next[3]=0,注意:这边的后缀不是从a开始的,是a之前的,所以应该是i开始的,如果从a开始得到1,是错误的。依据正确的算法,得到下面的next值,由于o之前没有元素,设next[0]=-1:
2.2 KMP之于BF的改进和查找模式
KMP与BF的查找(或者说改进)是,以上图的BF比较为例:
当比较到P的第六位的时候,BF会将M[1]与p[0]进行比较,而KMP则会先算出next[j]的值,这边j=5,next[5]=2,所以此时M[i]的i=5,p会将移动next[5]的长度,即2
个长度两者进行比较,这样减少了时间复杂度.此时比较的情况如图:
此时进行比较的是M的D和P的I,同时我们也发现i之前的两位与D之前的两位是相同的,a,b就是next【5】可以求出的可以移动的那两位。
3.代码
上面的是理论的,接下来就是代码的部分了,所使用的是java语言。下面是求next的部分。。
private static int[] nextcal(char[] pattern) {
//初始化next[0]的值
//定义两个变量,i,j分别表示模式串的开头,结尾
int i=-1;
int j=0;
//模式串的长度,用来控制结束时间
int pattern_len=pattern.length;
int next[]=new int[pattern_len];
//初始化next[0]的值
next[0]=-1;
//从next[0]开始赋值
while(j<pattern_len-1)
{
//pattern[i],pattern[j]分别表示第j个字符额前缀和后缀
//i=-1表示未找到前缀与后缀相等,i即next【j-1】
if(i==-1 || pattern[i]==pattern[j])
{
i++;
j++;
next[j]=i;
}else
{
i=next[i];
}
}
return next;
}
总结,关键是怎么求出next数组的值,还有kmp运用的限制条件,以及-1的使用
附:完整代码:欢迎关注我的github账号:chunrong918