POJ - 2752 Seek the Name, Seek the Fame(KMP中对next数组的前缀后缀匹配应用)

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

题意:输入一个串,找到该串中所有前缀和后缀相等的长度,如例1中
ab———————–ab
abab—————-abab
ababcabab-ababcabab
ababcababababcabab-ababcababababcabab
其中串长度本身必为一种解
此处可根据next数组得出结果
next数组所存储的是最长前缀后缀相等的长度。因此在原串中,除去串长这种解,第二个解就是next[len]的值。
原串的前缀后缀求出后,前缀后缀的前缀后缀相等长度又在next数组中有体现,只需按照next数组中给定的next【i】值回溯,即可从长到短的顺序找到所有前缀后缀相等长度。递归输出即可。

这里写图片描述
主传的前缀和后缀的前缀和后缀相等
主串的前缀和后缀相等
主串

假设黑色线来代表字符串str,其长度是len,红色线的长度代表next[len],
根据next数组定义易得前缀的next[len]长度的子串和后缀next[len]长度的子串完全相同(也就是两条线所对应的位置)。
我们再求出next[len]位置处的next值,也就是图中黄线对应的长度。
同样可以得到两个黄线对应的子串肯定完全相同,又由于第二段黄线属于左侧红线的后缀,
所以又能得到它肯定也是整个字符串的后缀。
所以对于这道题,求出len处的next值,并递归的向下求出所有的next值,得到的就是答案。

#include<stdio.h>///要找前缀后缀相同的,即利用KMP中NEXT数组里子串的重复性质来实现
#include<string.h>///NEXT数组中,最后一位字符的next值表示从头到中间某一位,和中间某一位到末尾字符串相等
char S[400005];///这就是模式串中前缀和后缀的最长相等位置,然后在前缀和后缀中继续找next值,即前缀和后缀的相等的前缀和后缀,这样递归下去可以得到所有的前缀和后缀的前缀和后缀的相等串
int next[400005];
void kmp_pre(char x[],int m)
{
    int i,j;
    j=next[0]=-1;
    i=0;
    while(i<m)
    {
        while(j!=-1&&x[i]!=x[j])j=next[j];
        next[++i]=++j;
    }
}
void print_back(int x)
{
    if(next[x]==0)return;
    print_back(next[x]);
    printf("%d ",next[x]);
}
int main()
{
    while(scanf("%s",S)!=EOF)
    {
        int len=strlen(S);
        if(len==1)
        {
            printf("1\n");
            continue;
        }
        kmp_pre(S,len);
        print_back(len);///注意next数组中每一位表示此之前一位是否和前缀相等,也就说如果是len-1位的next值其实表示的是len-2位字符是否和前缀中的字符相等
        printf("%d\n",len);///因此要使后缀(最末尾位的字符)和前缀相等,应该使用next中len位置的的值,表示跳到
    }
}
posted @ 2018-03-09 20:27  KuroNekonano  阅读(142)  评论(0编辑  收藏  举报