题意:给一个字符串S,找出一个最长的子串E,使得S可以写成‘EAEBE’的形式,其中A、B是任意字符串,可空。求E的最大长度。
思路:求前缀和后缀的最大匹配,可以用KMP算法里的next数组;求前缀和中缀的最长匹配,可以用扩展KMP,这里是跟自身匹配,所以搞一次扩展KMP里的求next数组就行了。
考虑到可能中间存在循环节导致中缀匹配的长度大于结果,从后缀匹配的结果入手,对于每个后缀匹配的结果,遍历是否有中缀匹配结果满足,有就输出答案,否则缩小后缀匹配的值继续遍历。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 1000005;
typedef long long ll;
int nxt[maxn];
char str[maxn];
int extend[maxn];
void get_extend(char str[]){//扩展KMP
int i = 0, j, pos;
int len = strlen(str);
extend[0] = len;
while(i + 1 < len && str[i] == str[i + 1]){
++i;
}
extend[1] = i;
pos = 1;
for(i=2; i<len; ++i){
if(extend[i - pos] < pos + extend[pos] - i){
extend[i] = extend[i - pos];
} else {
j = extend[pos] + pos - i;
if(j < 0){
j = 0;
}
while(i + j < len && str[i + j] == str[j]){
++j;
}
extend[i] = j;
pos = i;
}
}
}
void get_next(char s[], int next[]){//KMP算法中的获取next数组
int len = strlen(s);
next[0] = -1;
int index;
for(int i=1; i<len; ++i){
index = next[i - 1];
while(index >= 0 && s[i] != s[index + 1]){
index = next[index];
}
if(s[i] == s[index + 1]){
next[i] = index + 1;
} else {
next[i] = -1;
}
}
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%s", str);
get_extend(str);
int len = strlen(str);
get_next(str, nxt);
int tmp = nxt[len - 1], f = 0;
while(!f && tmp != -1){
for(int i=0; i<len; ++i){
if(extend[i] > tmp && tmp < i && i + tmp + tmp + 1 < len){
//tmp是后缀匹配的长度减一,此处保证前中后缀不会相互覆盖
f = 1;
break;
}
}
if(!f){
tmp = nxt[tmp];
}
}
printf("%d\n", tmp + 1);
}
return 0;
}