用途
解决最长回文子串
时间复杂度
O(n)
预处理
每一个字符左右加上特殊字符:简化奇偶回文串,使其处理方法相同。
最开始加上另一种特殊字符:避免算回文起始位置的时候下标为负。
符号含义
arr[] 预处理后数组
p[i] 以arr[i] 为中心的最长回文半径
right 之前处理的回文串最右到达的位置
mid right对应的回文中心
i 当前处理的回文中心
j i关于mid对称点 j = mid * 2 - i
ind 最长回文子串的回文中心
// left right关于mid对称点
过程
X回文:以x为中心的回文子串
第一种情况:J回文包含在mid回文里面。由于I, J关于mid对称,所以I回文长度与J回文长度一致。
第二种情况:J回文左端点小于left。则对于I回文,超出right的字符未知,采用暴力的方法。I回文长度从right - i开始暴力更新,之后更新mid和right。
结果
最大回文子串长度maxlen = max(p[ind] - 1);
起始下标index = ( ind - p[ind] ) / 2;
代码
//hdu 3068
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1.2e5 + 7;
char s[maxn];
int maxlen;
int index;
void Manacher()
{
int p[2 * maxn + 2];
char arr[2 * maxn + 2];
int mid = 1, right = 1;
int ind = 0;
int len = strlen(s);
for(int i = len; i >= 1; i --)
{
arr[i * 2 + 1] = '#';
arr[i * 2] = s[i - 1];
}
arr[1] = '#';
arr[0] = '$';
int lens = len * 2 + 2;
for(int i = 2; i < lens; i ++)
{
if(i < right)
{
p[i] = min(p[2 * mid - i], right - i);
}
else
p[i] = 1;
while(i - p[i] > 0 && i + p[i] < lens && arr[i + p[i]] == arr[i - p[i]])
p[i] ++;
if(i + p[i] > right)
{
mid = i;
right = i + p[i];
}
if(p[i] > p[ind])
ind = i;
}
maxlen = p[ind] - 1;
index = (ind - p[ind]) / 2;
}
int main()
{
while(scanf("%s", s)!= EOF )
{
Manacher();
cout<<maxlen<<endl;
for(int i = index; i < index + maxlen; i ++)
cout<<s[i];
cout<<endl;
}
}