【介绍】
Manacher可以线性解决最长回文子串的问题。
【思想】
Ps:用Manacher的时候,我们可以想到一个小办法减轻代码的长度,就是在每个字符之间加一个另类的字符也就是不同于其他字符的字符(比如处理只包含小写字母的字符串我们可以添加‘~’,首位也加。例如aba变成了~a~b~a~),这样原串中的所有字符都处在偶位,容易处理(否则就要判断是奇数长度的回文串还是偶数长度的回文串)。但是这个小办法也有负面也就是提高了空间复杂度。但加了以后代码非常好写,博主比较推荐
定义 p[x] 表示目前在第x位,向两边能推到的最大距离。
定义
Pos
表示目前的中点,
R
表示从中点所能推到的最大右端点,
我们该如何得出 p[x] 的转移方程。分类讨论,如下:
①: x<R
设
x
的对称点为
但是有一种情况要考虑,如果 y−p[y]<L ,那么就已经越界了,所以只能推到 y−L 即 R−x 。
所以 p[x]=min(p[2∗Pos−x],R−x)
②: x>=R
这时候就只能暴力往后退,然后更新 Pos 和 R <script type="math/tex" id="MathJax-Element-58">R</script>。
综上所述,很容易发现时间复杂度是线性的。
【模板】
int Manacher(char *s)
{
int len=strlen(s+1);
for (int i=1; i<=len; i++) c[2*i-1]='~',c[2*i]=s[i]; c[len=2*len+1]='~';
int Pos=0,R=0,MAX=0;
for (int i=1; i<=len; i++)
{
if (i<R) p[i]=min(p[2*Pos-i],R-i); else p[i]=1;//判断类别
while (1<=i-p[i]&&i+p[i]<=len&&c[i-p[i]]==c[i+p[i]]) p[i]++;//暴力往后推
if (i+p[i]>R) {R=i+p[i]; Pos=i;}//更新Pos和R
MAX=max(MAX,p[i]-1);
}
return MAX;
}