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

题意:

要求你给出每个前后缀相同的串的长度,比如: "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;
}


posted @ 2018-07-14 11:49  KirinSB  阅读(194)  评论(0编辑  收藏  举报