http://codeforces.com/problemset/problem/126/B-------》》》题目链接
题目大意:
给出一个字符串,找出一个子串既是它的前缀,也是它的后缀,还是一个非后缀也非前缀的子
题目分析:
本来挺简单的一个题,最开始想复杂了,还用了后缀数组,醉了。
这个题主要用的是kmp的next数组,首先我们要了解next数组的定义,next[i]表示以i为末尾的子串的后缀与能够匹配的整个串的最长的前缀。
然后我们可以知道后缀与前缀的最长相同的长度,现在是满足后缀和前缀的最长子串的情况。
然后我们利用hash除了以最后一个字符结尾的情况所有的与前缀匹配的长度。
最后我们利用next数组的性质,如果当前的匹配的长度在hash表中找不到,那么证明不存在非前缀与非后缀的子串符合条件,那么x=next[x],也就是跳转到当前位置失配的重新匹配的位置(免去重复匹配的部分),也就是小于当前情况的最大的子串的后缀和前缀匹配的情况,然后再查hash表。知道找到答案为止,找不到答案证明不存在解。
自己做的图解:
如图x2为x1失配时下一步将要用来对比的点,此时说明前缀w1和后缀w2是最长的相同的前后缀,接下来要找有没有既不是前缀也不是后缀的一段,这样就推出x3,原因是如果x3存在,那么前缀w3和后缀w4是最长的相同的前后缀,那么w4就符合要找的那一段,因为它既和前缀w3相同,又和后缀w5相同(原因是w1和w2相同);
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
int hash_s[1000001];//hash[i]表示i点存不存在
char s[1000001];
int next_s[1000001];
//next_s[i]表示点i之前的字符串最长相同的前后缀的前缀的下一个位置
ll getnext(){
ll len=strlen(s);
int i=0,j=-1;
next_s[0]=-1;
while(i<len){
if(j==-1||s[i]==s[j])next_s[++i]=++j;
else j=next_s[j];
}
return len;
}
int main(){
scanf("%s",s);
ll len=getnext();
for(ll i=2;i<len;i++){
hash_s[next_s[i]]=1;//如果next_s[i]存在,标记
}
//不能把next_s[len]加到hash表中,因为要找字符串中间的一段
ll x=next_s[len];
//如果hash表中不存在next_s[x];
while(!hash_s[x]&&x){
x=next_s[x];
}
if(!x){
cout<<"Just a legend";
}
else for(int i=0;i<x;i++){
cout<<s[i];
}
cout<<endl;
return 0;
}