#POJ 2752 Seek the Name, Seek the Fame (KMP)

Description

The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm:

Step1. Connect the father's name and the mother's name, to a new string S.
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S).

Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:)

Input

The input contains a number of test cases. Each test case occupies a single line that contains the string S described above.

Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000.

Output

For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.

Sample Input

ababcababababcabab
aaaaa

Sample Output

2 4 9 18
1 2 3 4 5

 题目大意 : 输入一个字符串, 输出所有前缀等于后缀的长度。

思路 : 首先KMP中next数组的作用就是表示前缀与后缀最大的公共长度, 但这道题不一样的是, 他要输出所有前缀等于后缀的可能长度, 而不是最大长度,刚开始看的时候我一点思路也没有, 然后试着把他的next数组表列了出来, 才有所发现 :

例如我输入 “ababcababababcabab”, 对应的就是“001201234343456789”, 再看一下答案, 是不是所有的答案都包含在其中呢?再想一想next数组的作用, i表示到i为止, 前缀与后缀的最大公共长度, 如果next数组的最后一位是0, 说明整个都没有前缀后缀相同的情况, 所以直接输出他的长度就好;用len表示总长, 如果next【len】 != 0的话, 就说明从0到next【len】这一截字符串和从len - next【len】 到llen这一截是相同的,而比他更小的前缀==后缀的长度, 只可能在next【len】的前面,那下一个长度是多少?就是next【len】!因为此时字符串的前next【len】项与后next【len】项是相等的,所以你看前面的部分也就等于是再看后面的部分,这是一个递归的过程, 就好像一个人每天把一根绳截一半一样, 前一半和后一半是相等的, 所以后一半可以不看了, 直到他不能再被截,这下应该明白了把^_^

AC代码 :

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 4e5 + 5;

string line;
int nxt[maxn], pre[maxn];
void getnext() {
    nxt[0] = -1;
    int i = 0, j = -1;
    while (i < line.size()) {
        if (j == -1 || line[i] == line[j])
            nxt[++i] = ++j;
        else
            j = nxt[j];
    }
}

int main()
{
    while (cin >> line) {
        memset(nxt, 0, sizeof(nxt));
        memset(pre, 0, sizeof(pre));
        getnext();
        int len_ = line.size();
        int ans = nxt[len_], X = 0;len_;
        if (!ans) {cout << len_ << endl; continue;}  // 自己就是循环体的情况
        pre[X++] = len_, pre[X++] = ans;  //把自己先存进去
        while (nxt[ans] != 0) {  //当不能再被截
            pre[X++] = nxt[ans];
            ans = nxt[ans];
        }
        for (int i = X - 1; i >= 0; i--) cout << pre[i] << " ";
        cout << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/91903191