学习KMP强烈推荐:严蔚敏老师的教学视频:http://www.56.com/u59/v_NjAwMzA0ODA.html
时长一小时,但绝对受益匪浅。
简单地总结一下我现在所掌握的KMP吧:
首先,需要明确的是KMP是处理什么问题的:求一个串(为了好理解下面的代码,姑且认为这个串为T)在另一个串(S)中完全匹配后的id,也就是说S中子串T的起始位置。
面对这个问题,我们很容易想到暴力的方法,就是两个for,一个一个去比,但是当出现:S:aa…aaas,T:aas时,复杂度就是O(m*n)(m:S的串长,n:T的串长),这样的复杂度做题时受不了的。于是,有个k啥,m啥,p啥的三个人研究出了一种算法,这种算法最坏的情况下是线性的,即复杂度是O(m+n);
了解kmp算法,首先需要了解kmp算法的核心和精华那就是next[]数组。(这个next数组的理解将至关重要,因为题目不可能是上述的那么简单,一般需要你在预处理next数组上做手脚)
首先我们不管next数组是什么,我们先来看一下next数组的作用:
假设我们已经在S中找到一段(从第i位开始)与T前半部分匹配的串,即 S的第i+j位与T的第j位不匹配,那么接下来我们如果按照暴力的方法,就是要比较S[i+1...i+j+1]与T[0...n],我们现在关注的是上述比较的前半部分,即:S[i+1...i+j+1]与T[0...j],有必要一个一个再比较一次么?没有。因为在已知的比较中我们知道S[i+1...i+j]与T[1...j]是相等的,所以就只是比较T[1...j]与T[0...j-1]了,如果我们预处理好一个数组,表示从第j位开始,前面next[j]位与T串的开头匹配,那么就很好判断了。如果第i位与next[j]相等,那么i++,j++,否则j=next[j]。直到两个串中的任意一个跑完。
这就是next数组的作用,和kmp算法的思路。
下面是自己的代码:
#include<cstdio>
#include<cstring>
const int mmax=100005;
char ss[mmax],tt[mmax];
int next[mmax];
void getnext()
{
int len=strlen(tt);
next[0]=-1;
for(int i=0,j=-1;i<len;)
{
if(j==-1 || tt[i]==tt[j])
{
i++,j++;
if(tt[i]!=tt[j])
next[i]=j;
else
next[i]=tt[j];
}
else
j=next[j];
}
}
int kmp()
{
int i,j;
int lens=strlen(ss);
int lent=strlen(tt);
for(i=0,j=0;i<lens && j<lent;)
{
if(j==-1 || ss[i]==tt[j])
i++,j++;
else
j=next[j];
}
if(j==lent)
return i-lent;
return -1;
}
int main()
{
while(scanf("%s %s",ss,tt)!=EOF)
{
getnext();
int ans=kmp();
printf("%d\n",ans);
}
return 0;
}