马拉车算法
Manacher算法是由题目“求字符串中最长回文子串的长度”而来。比如 abcdcb 的最长回文子串为 bcdcb ,其长度为5。
回文:正着念,反着念都一样
暴力解不容易,要分情况 解决长度为奇数和长度为偶数 回文的问题
具体做法:以每个位置为中心,向两边扩。(只适合于 长度为奇数的情况)
但是偶回文就扩不了了!
下图,无论是从哪一个数字开始扩,回文长度 都只能是1
这种情况下,我们只能向 字符串中各个字符之间 加东西!
比如这种情况,既有奇回文,又有偶回文
具体怎么插入呢?如下图:
数字的含义 是该位置的回文长度
最长回文就是最大值除以2,11/2=5
在这种情况下,无论是奇回文,还是偶回文,我们都可以找到!
注意:加的字符串。不仅仅只能为#,加什么都行,不影响结论。
时间复杂度估计:O(N²) (因为实质上是一个等差数列1+2+ … )
而manacher算法 时间复杂度估计:O(N)
为进一步详细介绍,我们先简单介绍几个概念:
1.回文直径与回文半径:
2.回文半径数组 pArr : parr【位置】=回文半径
3.最右回文右边界 R : 来到的最右位置的字符 !
最右回文右边界对应的回文中心 C :
总结:
处理回文子串长度为偶数的问题:上面拿 abcdcb 来举例,其中 bcdcb 属于一个回文子串, 但如果回文子串长度为偶数呢?像
cabbac ,按照上面定义的“扩”的逻辑岂不是每个字符的回文半径都是0, 但事实上 cabbac 的最长回文子串的长度是6。
因为我们上面“扩”的逻辑默认是将回文子串当做奇数长度的串来看的, 因此我们在使用Manacher算法之前还需要将字符串处理一下, 这里有一个小技巧,那就是将字符串的首尾和每个字符之间加上一个特殊符号,这样就能将输入的串统一转为奇数长度的串了。比如 abba 处理过后为
#a#b#b#a ,这样的话就有charArr[4]=’#’ 的回文半径为4,也即原串的最大回文子串长度为4。
接下来分析,manacher算法是如何利用遍历过程中计算的 pArr 、 R 、 C 来为后续字符的回文半径的求解加速的
**情况1是,**遍历到的字符下标i 在 R 的右边(起初另 R=-1 ),这种情况下该字符的最大回文半径pArr[i] 的求解无法加速,只能一步步向外扩来求解。(暴力扩)
例子:
从0位置扩的时候,最右回文右边界 R在-1位置,( 即 i位置不再回文右边界里面,这个时候暴力扩就 完事了! )
0位置扩的时候,回文右边界 来到 0位置
所以,到了1的时候,回文右边界还是在1的左面,所以还是暴力扩
此时,回文右边界来到这儿 2的位置
当来到2的时候,发现在回文右边界里面了,这时介绍情况2。
情况2是,遍历到的字符下标 i 在回文右边界 R 内,这时 pArr[i] 的求解过程可以利用之前遍历的字符回文半径信息来加速。
分别做 cur 、 R 关于 C 的对称点L :
i一定在c的右面
根据c做 i 的对称点
我们有 每个位置回文半径的长度,且都纪录在 一个数组中(回文半径数组),
这个数组可以告诉我,求 i‘ 的回文区域是哪一段
例子:
i 和 i‘ 的回文半径在 L R之间
此时,i 位置的回文半径直接知道答案。
即,和 i‘ 一样
先证明 这一部分是回文:
如下图。1是回文,c整体是回文,2和c对称,所以,是一个镜像的关系,所以2是1的 逆序,所以2是回文
接下来证明 后面的不是回文。
逻辑顺序按1 2 3
可能性3:i‘ 自己的回文范围,L和R没报包住
例子:
长度直接为 i 到R
证明:
因为大回文,所以 x≠x‘
所以,x ≠ y
综上所述,共四种可能性:
- i 在 R 外
- i 在 R 内(分为3种情况)
2.1 i‘ 的回文半径在 L和R里面 O(1)
2.2 i‘ 的回文半径在 L和R外面 O(1)
2.3 i‘ 的回文半径在 跟L压线
下面讲2.3
例子:
每个字符都尝试向外扩到最大并更新 R (只增不减),每次 R 增加的量就是此次能扩的字符个数,而 R 到达串尾时问题的解就能确定了,因此时间复杂度就是每次扩操作检查的次数总和,也就是 R 的变化范围( -1~2N ,因为处理串时向串中添加了 N+1 个 # 字符),即O(1+2N)=O(N) 。
第一种可能性:
第二种可能性:
第三种可能性:
应用:
给你一个字符串,要求添加尽可能少的字符使其成为一个回文字符串。
思路:当 R 第一次到达串尾时,做 R 关于 C 的对称点 L ,将 L 之前的字符串逆序就是结果
前面不是回文的部分,逆序过来,就是答案。
如何做:
改写manacher算法
当发现回文右边界扫到了字符串最后一个位置,
这时候,得到了 c和回文 右边界 R,
也能得到L,
这时,L前面的,不是回文的部分逆序,直接出答案
偶回文情况:
进阶1 01.51.18 开始扩