给出一个只由小写英文字符(a,b,c,dots,y,z)组成的字符串(S),求(S)中最长回文串的长度,字符串长度为(n)
对于一个回文串
①当长度(len)是偶数时,关于最中间的两个字母对称
②当长度(len)是奇数时,关于最中间的一个字母对称
因此,进行统一,字符串首尾和每个字符间插入一个字符,使得长度为(2len + 1)
那么就变成了第②种情况
定义:
p[i] 表示以i为中心的最长回文半径,则p[i] - 1就是最长回文半径
设mx表示回文串中心为id,半径为(p[id])的回文串的最右边
那么在([id - p[id], id])和([id,id + p[id]])是关于id对称的串,那么进行遍历
设i,j是关于id对称的,那么对于回文串在([id - p[id],p[id] + id])这个区间都是对称的,满足(p[i] = p[j]),即(p[i] = p[2 * id - i])但如果(p[j])的回文串超出了最左边部分,那么p[i]的回文串半径是(m - i),那么(p[i] = min(p[2 * id - i], mx - i))
传送门
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 11e6 + 5;
int n,p[N << 1],ans;
char a[N],s[N << 1];
void change() {
s[0] = '@';
s[1] = '#';
for(int i = 0; i < n; i++) {
s[i * 2 + 2] = a[i];
s[i * 2 + 3] = '#';
}
n = n * 2 + 2;
s[n] = '$';
}
void manacher() {
int mx = 0, mid;
for(int i = 1; i <= n; i++) {
if(i < mx)
p[i] = min(p[mid * 2 - i], mx - i);
else p[i] = 1;
while(s[i - p[i]] == s[i + p[i]]) p[i]++;
if(i + p[i] > mx) {
mx = i + p[i];
mid = i;
}
}
}
int main() {
scanf("%s",a);
n = strlen(a);
change();
manacher();
for(int i = 0; i < n; i++)
ans = max(ans, p[i]);
printf("%d",ans - 1);
return 0;
}