题目描述
链接: 牛客链接.
链接: 洛谷题解.
题意:给一个字符串,求出其中最长的一个子串,满足既是前缀也是后缀,且在中间也至少出现过一次
题解
首先前缀和后缀相等,联想到kmp(kan mao pian)算法:
该子串既是以len-1结尾的后缀,也是串中以某一第i位置结尾的后缀,也是整个串的前缀。
(1)首先kmp算法处理出[0,len]位置的next值。
对于[0,len-1]的next存储的是失配的下一匹配位置;[1,len]可看作[0,len-1]中以各个位置为结尾的字符串前缀、后缀相等的子串长度。
(2)对于以len-1结尾的与前缀相等的后缀子串长度,若在[1,len-2]位置中也有相同长度的next[]值 ,则都等于前缀。因此在前缀、串中和后缀都出现满足条件。
故只要对k=next[len-1],若k长度未在[1,len-1]出现,则k=next[k];否则输出当前长度的后缀子串满足条件
代码
#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int nxt[maxn];
int cnt[maxn];
void getNext(string &p){
int k=-1,j=0,len=p.length();
nxt[0]=-1;
while(j<len){
if(k==-1||p[k]==p[j]){
nxt[j+1]=k+1;
j++; k++;
}else k=nxt[k];
}
for(int i=1;i<len-1;i++) cnt[nxt[i]]++;
}
void Solve(string &S){
int len=S.length(), k=nxt[len-1];
while(k>=0&&cnt[k]==0) k=nxt[k];
if(k<=0){
// k<=0,串中未出现
cout<<"Just a legend"<<endl;return;
}
for(int i=len-k-1;i<len-1;i++) cout<<S[i];
cout<<endl;
}
int main(){
string S; cin>>S;
S+='$';
getNext(S);
Solve(S);
}