作者:lykkk
链接:https://ac.nowcoder.com/discuss/193977
来源:牛客网
问题
什么是回文串,如果一个字符串正着度读和反着读是一样的,这个字符串就被称为回文串。
such as
noon level aaa bbb
既然有了回文,那就要有关于回文的问题,于是就有了——最长回文子串:给定一个字符串,求它的最长回文子串长度。
暴力
找出所有的子串,遍历每个子串判断他们是否为回文串。
时间复杂度
优化
因为回文串是对称的,根据这个性质,枚举每个位置,找在这个位置上能扩展到的最长回文串。
时间复杂度
Manacher算法
打开洛谷的模板题发现数据范围是
先分析优化后的暴力的不足。
1.对于长度为奇数的回文和长度为偶数的回文,它们的对称轴是不一样的,要分类讨论。
2.有些子串会被访问多次。
比如 :
char: a b a b a b a ...
i : 0 1 2 3 4 5 6 ...
我们枚举到第位:时第一个"aba"被遍历了一次;时第一个"aba"又被遍历了一次;时第一个"aba"双被遍历了一次;
.......……时第一个"aba"又双叒叕被遍历了一次。
处理字符串长度的奇偶性带来的对称轴不确定问题
如果字符串的长度都是奇数就好办了。
处理原来的字符串,在收尾和所有空隙插入一个相同的无关的字符,插入后原字符串中是回文的子串还是回文串,不是回文的子串的依然不是。
但字符串的长度都变成了
为什么是
如:
长度为奇数的字符串
ababa ---> @#a#b#a#b#a#
长度为偶数的字符串
1221 ---> @#1#2#2#1#
'@'用来防止数组越界
找最长回文串
回文半径:把一个回文串中最左或最右位置的字符到其对称轴的距离称为回文半径
在Manacher算法中,我们用
char : # a # b # c # b # a #
p[i] : 1 2 1 2 1 6 1 2 1 2 1
p[i] - 1 : 0 1 0 1 0 5 0 1 0 1 0
i : 1 2 3 4 5 6 7 8 9 10 11
显然,最大的
显然这个结论非常不显然,单从数值上看的话,插入完字符之后对于一个回文串的长度为 原串长度*2+1,等于 这个回文串回文半径*2+1,显然相等。
这样我们的问题就转换成了怎样快速的求出
在这里我们利用回文串的对称性扩展回文串,p[i]不再直接赋值为1,而是根据之前求出的p[j],0<j<i。
我们用
为什么要维护这些东西,因为我们要利用回文串的对称性来更新当前位置的值,维护了右边界()后就可以直接判断当前位置是否可以直接利用对称性来更新(因为之前找到的回文串最右端就是到,超出的话就不能利用对称性来更新了);是对称轴,用来求关于对称的位置。
中间的#懒得画了就
如图,假设我们已经求出了
以下内容为了方便我们定义:
- 串
表示以为对称轴的回文串(用红色的箭头表示);
- 串
表示以为对称轴的回文串(用蓝色的箭头表示);
- 串
表示以为对称轴的回文串(用绿色的箭头表示);
情况1:i < mx
如上图,利用回文串的性质,对于
但在这里又细分为了三种情况
(1)
显然此时
对于这种情况,串
如果可以向两边扩张的话,
(2)
显然此时
与(1)不同的是,串
应该很显然,一比划就知道。
(3)
此时
这时我们只能确定串
同样,这时我们的串
如果串
情况2:i >= mx
这时之前记录的信息都用不上了,于是
综上所述
if
代码
P3805 【模板】manacher算法
#include
与作者交流:https://ac.nowcoder.com/discuss/193977
更多算法和题解:https://ac.nowcoder.com/acm/contest/discuss