manacher算法是用来处理最大回文子串的算法,时间复杂度为O(n);上一篇文章说的中心扩展算法时间复杂度为O(n^2),遍历O(n),对每个元素都中心扩展时间复杂度O(n)。
关于manacher算法的原理可以参考(也是我今天找的比较好的资料):
湘潭大学2019年ACM集训专题-manacher&回文树
这个看完manacher就好了,大概二十来分钟,看两遍。
[译+改]最长回文子串(Longest Palindromic Substring) Part II
manacher算法核心就是利用回文字符串自身的性质减少字符的中心扩展次数,同时利用加’#'字符可以避免奇偶分类讨论,回文数的处理上 中心扩展法是必不可少的,也是学习manacher的前提。
char * longestPalindrome(char * s)
{
int i_mirror = 0, diff = 0, maxlen = 0, centerIndex = 0, C = 0, R = 0;
// 预处理过程 加'#'
char t[2048];
int p[1024];
unsigned int i = 0, j = 1;
t[0] = '#';
for (; i < strlen(s); i++, j++)
{
t[j++] = s[i];
t[j] = '#';
}
t[j] = '\0';
// 预处理结束
for (i = 0; i < strlen(t); i++)
{
i_mirror = 2*C - i; // 确定i关于C的镜像
diff = R - i;
if (diff >= 0) // i 在C与R的中间
{
if (p[i_mirror] < diff) //如果i_mirror的回文半径在L后面
p[i] = p[i_mirror];
else
{
p[i] = diff;
while (t[i+p[i]+1] == t[i-p[i]-1]) // 中心扩展法,更新R、更新C
{
p[i] ++;
C = i;
R = i + p[i];
}
}
}
else // 当i在R之和
{
p[i] = 0; // 初始化
while (t[i+p[i]+1] == t[i-p[i]-1]) // 只能中心扩展
{
p[i] ++;
C = i;
R = i + p[i];
}
}
}
// 确定最大长度和中心索引的下标
for (i = 1; i < strlen(t) - 1; i ++)
{
if (p[i] > maxlen)
{
maxlen = p[i];
centerIndex = i;
}
}
s[(centerIndex)/2 -1 + maxlen] = '\0'; // 原地修改字符串
return s + (centerIndex/2 - 1); // 返回,碰到'\0'最大回文子串结束
}
注意一下,上述代码直接提交leetcode是有问题的。
Line 37: Char 28: runtime error: index -1 out of bounds for type ‘char [2048]’ (solution.c)
大意就是在
while (t[i+p[i]+1] == t[i-p[i]-1])
出现了t[-1]这个情况。但是我用sublime配置c环境运行没出现这个问题,用printf打印调试也没问题。用win10 + codeblocks的13.12版本运行也没问题,准备用codeblocks单步调试的,但是试了好几次,还没调试完,电脑风扇就转得飞起,codeblocks也出现未响应,遂放弃;但是在debug过程中,发现 i-p[i]-1 的值没问题。
测试结果如下图: