题目大意:给你一个字符串,让你找出既是前缀同时又是后缀的子串在主串中的位置,如果有多个,按升序输出。
分析:考察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;
}