POJ2752 Seek the Name, Seek the Fame KMP-next数组的应用

题目大意:给你一个字符串,让你找出既是前缀同时又是后缀的子串在主串中的位置,如果有多个,按升序输出。


分析:考察KMP算法中对next数组的理解。我们知道next[ j ]纪录的是字符串第j个位置之前的next[ j ]个连续的字符和该串的长度为next[ j ]的前缀是相同的。既然如此,要判断一个后缀是否等于前缀,只需看next[ len ]是否等于0即可,next[ len ]!=0就意味着有一个长度为next[ len ]的前缀和后缀相等。这样我们就得到了一个一个既是前缀又是后缀的子串了,并且这个子串的第一个字符在主串的next[ len ]位置处。然后让位置光标i=next[ len ],由于此时的光标所在的位置(即next[ len ])和主串有相同的后缀,所以我们只需再判断next[ next[len] ]是否为0,便又可以得到一个长度为next[ next[len] ]的前缀后缀子串了,这样递推下去,直至找到一个next数组值为0的点为止。



实现代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 400005
int next[maxn];
char str[maxn];
int len;
int ans[maxn];//纪录前缀后缀子串在主串中的位置
void init_next()//获得next数组
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<len)
    {
        if(j==-1||str[i]==str[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
void solve()//求找前缀后缀子串
{
    len=strlen(str);
    init_next();
    ans[0]=len;
    int cnt=1;//纪录ans数组元素的个数
    int i=len;//纪录主串位置光标
    while(next[i])
    {
        ans[cnt++]=next[i];
        i=next[i];
    }
    for(i=cnt-1;i>=0;i--)
      printf("%d ",ans[i]);
    printf("\n");
}
int main()
{
    while(scanf("%s",str)!=-1)
      solve();
    return 0;
}



你可能感兴趣的:(POJ2752 Seek the Name, Seek the Fame KMP-next数组的应用)