KMP算法精髓在于next数组上:
1.next[]数组的定义。对于字符串s的第i个字符s[i],next[i]定义为字符s[i]前面最多有多少个连续的字符和字符串s从初始位置开始的字符匹配 。
因此,对next数组实行逆序跳转输出,可得到 POJ-Seek the Name, Seek the Fame 此题答案
2.S的长度为len,S存在循环子串,当且仅当,len可以被len - next[len]整除,最短循环子串为S[len - next[len]] 。
3.基于2,可以查找当前位置之前是否存在循环子串:i%(i-next[i])==0 ;
给出KMP算法模板:
const int maxn=1000000+50;
int Next[maxn];
void getNext(char* s){
int ls=strlen(s);
memset(Next,0,sizeof(Next));
for(int i=1;i<ls;i++){
int j=Next[i];
while(j && s[i]!=s[j])
j=Next[j];
Next[i+1]=(s[i]==s[j])?j+1:0;
}
}
int KMP(char* a,char* s){
getNext(s); //模式串
int ans=0,j=0;
int la=strlen(a);
int ls=strlen(s);
for(int i=0;i<la;i++){
while(j && a[i]!=s[j])
j=Next[j];
if(a[i]==s[j])
j++;
if(j==ls){
ans++;
}
}
return ans;
}
java版本:
static void getNext(String s,int[] Next){
int ls=s.length();
for(int i=1;i<ls;i++){
int j=Next[i];
while(j>0 && s.charAt(i)!=s.charAt(j))
j=Next[j];
Next[i+1]=(s.charAt(i)==s.charAt(j))?j+1:0;
}
}
static int indexOf (String a,String s){
int[] Next=new int[10000];
getNext(s,Next); //模式串
int ans=0,j=0;
int la=a.length();
int ls=s.length();
for(int i=0;i<la;i++){
while(j>0 && a.charAt(i)!=s.charAt(j))
j=Next[j];
if(a.charAt(i)==s.charAt(j))
j++;
if(j==ls){
return i-j+1;
}
}
return -1;
}