首页 > 代码库 > POJ2752 Seek the Name, Seek the Fame next数组应用

POJ2752 Seek the Name, Seek the Fame next数组应用

题目描述

给出一个字符串,求出存在多少子串,使得这些子串既是主串的前缀,又是主串的后缀。从小到大依次输出这些子串的长度。

Sample Input
ababcababababcabab
aaaaa

Sample Output
2 4 9 18
1 2 3 4 5



解题思路:

我们首先知道最大的那个数肯定是主串本身的长度。除去这个最大的应该是next[len].由于我们肯定是由大往小找,而题目要求输出时从小到大输出,所以考虑使用栈结构。找到了next[len]后,主串的前后都有一段长度为next[len]的相同串,故我们考虑next[ next[len]  ] 即考虑前缀这边的相同前后缀,由next性质可以知道,前缀的后缀就是后缀的后缀,所以也就是原主串的更小的前后缀相同。

所以一直递归下去就可以了,直到next=0为止。

需要注意的是,next数组不能开优化,应该给予next最本质的定义,否则会出错。

代码如下

#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
void GetNext(char* p,int next[])
{
    int pLen = strlen(p);
    int k = -1;//k记录的是next[j]
    next[0] = k;
    int j = 0;
    while (j < pLen) {
        /** next[j]=-1时,next[j+1]肯定是0;p[j]=p[k]时,next[j+1]=next[j]+1 */
        if (k == -1 || p[j] == p[k]) {
            ++k;
            ++j;
           /* if(p[j] != p[k]) */next[j] = k;
           // else next[j] = next[k];
        }
        else k = next[k];
    }
}
const int maxn = 400010;
char s[maxn];
int next[maxn];
stack<int> p;
int main()
{
    while(scanf("%s",s) != EOF) {
        GetNext(s,next);
        int k = strlen(s);
        while(next[k] > 0) {
            p.push(next[k]);
            k = next[k];
        }
        while(!p.empty()) {
            printf("%d ",p.top());
            p.pop();
        }
        printf("%d",strlen(s));
        printf("\n");
    }
    return 0;
}


POJ2752 Seek the Name, Seek the Fame next数组应用