题意:
T次询问,每次给你一个字符串s(|s| <= 1e6),找到一个最长的子串,出现在s的串首、串中、串尾位置,互不重叠。输出这个子串的长度。
思路:
先用扩展kmp处理出s每位s[i]开头的的子串与前缀的最大长度,保存在nxt数组中,从尾部开始遍历nxt数组,如果i + nxt[i] = |s|(s的长度),则说明检索出了串首、串尾的两个子串,那再检索串中的子串是否存在,并在检索的过程中保证串首、串中、串尾的子串互不重叠。
code:
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
char s[maxn];
int nxt[maxn];
void get_N(){
int len = strlen(s);
nxt[0] = len;
int j = 0;
while(j + 1 < len && s[j] == s[j + 1]) j++; nxt[1] = j;
int p = 1;
for(int i = 2; i < len; i++){
if(p + nxt[p] > i + nxt[i - p]) nxt[i] = nxt[i - p];
else{
j = 0;
while(i + j < len && s[j] == s[i + j]) j++; nxt[i] = j;
p = i;
}
}
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%s", s);
get_N();
int len = strlen(s);
int mx = 0;
for(int i = len - 1; i >= 0; i--){
if(nxt[i] + i == len) {
int j = i;
while(j--){
if(j >= nxt[i] && nxt[j] >= nxt[i] && j + nxt[i] - 1 < i) //检索串中子串,并保证不重叠
mx = max(mx, nxt[i]);
}
}
}
printf("%d\n", mx);
}
}