题目链接:https://vjudge.net/problem/CodeForces-126B
题意:一个字符串,找出最长的子串t,它既是前缀又是后缀,还出现在中间。输出t,不存在则输出Just a legend。
这个题KMP的next数组的理解还是要有的,next[i]表示在i之前,最长的公共前缀后缀的长度。
所以说,我们首先要看看是否存在公共前缀后缀,如果有,这只是保证了可能有解,因为我们还要看中间是否出现过,这个时候,我们让i=nxt[i],继续看这个nxt[i]是否出现过,为什么呢?因为你此往前移动是,就相当于产生了一个可能的答案,但是我们需要中间也出现过,所以就要判断这个nxt[i]值是否出现过,当出现过的就是答案。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<string>
#include<vector>
#include<stack>
#include<map>
#include<set>
const int maxn=1000005;
int next[maxn];
int vis[maxn];
char q[maxn];
void kmp(char w[])
{
int len=strlen(w);
int i=0;
int j=-1;
next[0]=-1;
while(i<len)
{
if(j==-1||w[i]==w[j])
{
i++;
j++;
next[i]=j;
}
else j=next[j];
}
for(int i=0;i<len;i++) ///字符串中的next数组中1——len-1的vis设为1.
{ ///表示该next【i】出现过。
vis[next[i]]=1;
}
}
int main()
{
scanf("%s",q);
kmp(q);
int i=strlen(q);
int flag=1;
while(next[i]) ///如果最后一个字母的next数组的值为0,则说明没有相同的前缀和后缀,不符题意。
{
if(vis[next[i]]) ///如果在next的数值在最后一个字母之前已经出现过,则,说明在中间出现过。
{
for(int j=0;j<next[i];j++)
{
printf("%c",q[j]);
}
flag=0;
break;
}
i=next[i]; ///最长前后缀在中间没出现过,则缩减长度,只能在当前最大前缀中找次最长前缀等于后缀,所以长度就是缩短为next[i]了
}
if(flag==0) printf("\n");
else printf("Just a legend\n");
}