一、算法思想:
常规方法求一个字符串的最大回文子串可以用一个两层循环实现,外循环i表示对称轴位置,内循环以i为对称轴向两边遍历检查元素是否相等。但是这样会有多余操作,以下图为例:
(图片来源:https://segmentfault.com/a/1190000003914228)
假如外循环遍历到i位置,pos是之前遍历过的位置,且红色部分是以pos为对称轴的一个回文子序列边界,可以推断,i关于pos对称的位置j,以j为对称轴的回文子序列必定与以为对称轴的回文子序列有交集,因此求以i为对称轴的回文子序列的半径时就可以利用求过的j的半径,除去多余的操作。
二、代码:
/*
name:
author:followStep
description:
date:2018/3/17 14:12:27
*/
//#define LOCALE
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXLEN 100000
char str[MAXLEN]; //原字符串
char assi[MAXLEN*2]; //辅助字符串
int r[MAXLEN*2]; //半径
void init();
int manacher();
int main()
{
#ifdef LOCALE
freopn(".in", "r", stdin)
freopen(".out", "w", stdout)
#endif
scanf("%s", str);
init();
int maxLen = manacher();
printf("%d", maxLen);
return 0;
}
void init() //给str插入'#'消除奇偶判断
{
int len = strlen(str);
assi[0] = '#';
int j = 1;
for(int i=0; i<len; i++){
assi[j++] = str[i];
assi[j++] = '#';
}
assi[j] = '\0';
}
int manacher()
{
int len = strlen(assi);
int bound=0, pos=0; //bound保存目前的最大回文子序列边界,pos即对称轴
int maxLen = 0;
for(int i=0; i<len; i++){
if(i < bound)
r[i] = min(r[2*pos-i], bound-i+1); //2*pos-i即j位置,bound-i+1表示以j为对称轴的回文子序列边界有可能超过bound边界,因此二者取其小
else
r[i] = 1;
while(i-r[i]>=0 && i+r[i]<len && assi[i-r[i]] == assi[i+r[i]])
r[i]++;
if(bound < i+r[i]-1){ //更新pos及bound
pos = i;
bound = i+r[i]-1;
}
if(r[i]-1 > maxLen)
maxLen = r[i]-1;
}
return maxLen;
}