O(n)时间求 最长回文子串 Manacher算法
- 回文字符串分为奇回文和偶回文,在字符串中间插入任意字符使得串变成奇回文串
暴力思想:肯定是找一个点往两边任意扩展,遍历一次,
Manacher时间为O(n)
- 开一个数组
p[]记录 以点i为中点 的最长回文串的半径, - 假设前
i-1个点的p[]都已经求出来来,现在考虑p[i]如何推导
重点:
3. R是p[1]~p[i-1]中推出来的右端最远最长回文子串的右端点,且用pos记录下来,每一步更新pos+R,既然R知道了,L也知道(没啥意义)
4. 当前遍历到i点,j是与i对称的点,且 $j=pos-(i-pos)$ -> $j=2pos-i$,我们可以通过j点来得到i点的p[i]值
5. 此时i j R 有三种情况
a. 第一个图中红色都在[L,R]范围内,R-i>p[j],直接得到p[i]的值,p[i]=p[j]
b.
此时j点的回文子串只有一部分在[L,R](最大的回文子串)中,那么超出范围的肯定不符合要求,R-i<p[j]所以p[i]=R-i
c. 剩下一个情况应该都看出来了,就是i>=R,现在只能往两边暴力扩展了
总结步骤:
- 先更新
p[],有三种情况 - 向两边暴力扩展回文字符串,满足前两种情况这一步肯定扩展不出来新的回文串,所以不需要特殊判断是否
if(p[i]==1),所以这一步往两边扩展 - 更新
[L,R]右端最远的回文子串,并且记录pos的值, - 这是(插入字符的奇数字符串)上的一系列操作,我们要转化成源字符串上的位置与长度 这里是2个结论,
自己对比就可以知道了,
原字符串的位置:index = (resid - reslen)/2
源字符串的长度:len = reslen-1
- 在第一个添加一个与其他都不同的字符,就是为了
index正确求出来
1 | |
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!
