KMP算法主要解决字符串匹配问题,应用广泛。主要的思想就是尽量不让以前走的路白走,相对于暴力算法,如果匹配失败,不会直接退回到最前面的位置,而是让字符串后退,那是怎么实现的呢?首先引入了next数组,而next数组的求法其实和KMP算法的核心思想是一样的,首先看下什么是next数组。
next数组就是子串s[0...i]的最长相等前后缀的前缀最后一位的下标。前后缀不能是子串本身。
例如字符串ababaab
已知next[0]=-1,next[1]=-1,next[2]=0,next[3]=1,我们来求一下next[4]
在next[3]的基础上,箭头两个已经相等,是不是只要下一个相等,就是最长相等前后缀了,即s[next[3]+1]=s[4],当然这是最简单的情况,那我们继续来求next[5]
可恶箭头的下一个竟然不相等了!那肯定是前后缀缩短长度了。 缩到多短呢,那肯定是听取前人的经验,到next[j]了,当他一直退退退都不能匹配,那就是推到-1也不能匹配,那就是没有前后缀相等的情况了,然而当我们突然发现s[j+1]等与s[5]了,我们要找的人来了,next[5]=j+1。
代码如下:
void nextval(string needle,int m){
int j=-1;
next[0]=-1;
for(int i=1;i<m;i++){
while(j!=-1&&needle[i]!=needle[j+1]){
j=next[j];
}
if(needle[i]==needle[j+1]) j++;
next[i]=j;
}
}
那么求next数组是干嘛用的呢,就是当j+1位失配时,j应该退回的位置,很容易理解,因为next就是前后缀相等的最大坐标,前缀等于后缀,那就让前缀退回到相等的后缀那里去。代码如下:
int strStr(string haystack, string needle) {
int m=needle.size();
int n=haystack.size();
nextval(needle,m);
int j=-1;
for(int i=0;i<n;i++){
while(j!=-1&&needle[j+1]!=haystack[i]){
j=next[j];
}
if(needle[j+1]==haystack[i]){
j++;
}
if(j==m-1) return i-m+1;//返回第一个匹配的下标,从0开始
}
return -1;//没有匹配的情况
}
其实还有有点云里雾里的,慢慢理解吧