POJ 2752 Seek the Name, Seek the Fame(KMP中next的理解)题解

时间:2022-11-09 08:26:20

题意:

要求你给出每个前后缀相同的串的长度,比如: "alala"的前缀分别为{"a", "al", "ala", "alal", "alala"}, 后缀分别为{"a", "la", "ala", "lala", "alala"}. 其中有{"a", "ala", "alala"}是相同的,所以答案是1,3,5。

链接

思路:

本题需要灵活运用next数组,要理解next的含义才能做。

next[i]代表长度为i的子串的前后缀匹配值,我们需要先求出当前主串的最大匹配度k,也就是前k个和后k个一样。然后我们怎么得到s[1...k-1]和s[len-k+2...len]是否相等(这里的数字不是下标),即前k-1个和后k-1个怎么比较是否相同。这里就需要深入理解next了。我们得到了k那么next[next[k]]代表着前k个的前缀和后k个的后缀的最大匹配度,然后如此递归即可得到答案。这里建议画图理解一下

代码:

#include<iostream>
#include<algorithm>
const int N = 400000+5;
const int INF = 0x3f3f3f3f;
using namespace std;
int fail[N],ans[N];
char p[N];
void getFail(){
fail[0] = -1;
int j = 0,k = -1;
int len = strlen(p);
while(j <= len){
if(k == -1 || p[j] == p[k]){
fail[++j] = ++k;
}
else{
k = fail[k];
}
}
}
/*int KMP(){
int num = 0;
getFail();
int i = 0,j = 0;
int lent = strlen(t),lenp = strlen(p);
while(i < lent){
if(j == -1 || t[i] == p[j]){
i++;
j++;
if(j == lenp) num++;
}
else{
j = fail[j];
}
}
return num;
}*/
int main(){
int cnt,Case = 1;
while(scanf("%s",p) != EOF){
getFail();
cnt = 1;
int len = strlen(p);
ans[0] = len; //本身肯定是
len = fail[len]; //最大前后缀匹配值
while(fail[len] >= 0){
ans[cnt++] = len;
len = fail[len];
}
for(int i = cnt - 1;i >=0;i--){
if(i != cnt-1) printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
return 0;
}