Manacher
2021-10-03 / ryanxw
Manacher
1. 概念
用于求取字符串中最大的回文子串,需要考虑的是奇回文 or 偶回文
- 奇回文:123a321,其中字符a所处的位置为对称轴,实轴
- 偶回文:1221,其中两个2中间的位置为对称轴,虚轴
所以在判断回文串时需要先处理一下字符串本身,让虚轴显示出来,比如加入特殊字符”#”来保证虚轴可以看到。
- 不用担心特殊字符和字符串中的原字符发生冲突,因为是对称的,虚轴只会和虚轴相比较。
- 处理过后的样子:
- 奇回文:#1#2#3#a#3#2#1#
- 偶回文:#1#2#2#1#
2. 实现原理
2.1 暴力解法
假设字符串的长度是N,处理成特殊字符后每个位置都开始向两边扩,比较字符,记录好最大的回文长度就ok,每次有更大的就更新。
- 时间复杂度O(N^2)
2.2 manancher解法
解决掉在暴力解法中一些地方无需尝试扩,比较,直接向后跳即可。
几个概念
要先熟悉几个概念
- 回文半径
- 最右回文边界R(R一定停在特殊字符上,因为只有实际字符才存在不同,扩不动的情况)
- 最有回文边界的中心C(只记录第一次【即最早】冲到R时候的C的位置,此时为最长情况)
几种拓扑图(核心)
初始化遍历字符串的下标 Index = 0
- 最右回文边界 R 在 Index 的左边,即 R < Index 这种情况下没有优化空间,只能暴力匹配
- 最右回文边界 R 在 Index 的右边,即 R > Index
- Index 位置的对称点 Index’ 的回文范围就在 (L,R) 内 由图可以知道在对称点 Index’ 的位置已经扩到了 X ≠ Y 处不能再向两边扩了。而目前Center所处的位置 C 所扩到最大的边界时(L,R),所以 P == Y, Q == X。而 X ≠ Y,则 P ≠ Q
- Index位置的对称点 Index’ 的回文范围只有部分在 (L,R) 内 此时Index能扩充的范围就是(Index,R)。原因:
- 由图可知目前 Center 所处的位置 C 所扩到最大的边界时(L,R),所以 P ≠ Q。
- 而P在(i’L,i’R)这个当时以 Index’ 为中心的回文串中,则一定有一个 X 和 P 关于Index’ 对称,即 P == X
- X 又在以 C 为中心的回文串(L,R)中,则必存在一个 Y 和 X 关于 C 对称,即X == Y
- 因为 P == X,X == Y,所以 P == Y,而 P ≠ Q,则Y≠Q,所以最多扩到(Index,R)
- 因为关于C对称
- Index位置的对称点 Index’ 的回文范围 (i’L,i’R) 中的 i’L 刚好和 (L,R) 的L重合 由图可以知道 :
- X == Y
- W ≠ Y,则 W ≠ X
- W ≠ Z
- 但是无法确认Z是否等于X,则只能暴力扩展去判断
总结分析
- case1:i 在 R 右面,暴力扩,i增长,时间复杂度O(n)
- case2:(i’L,i’R)在L内,不用扩,O(1)
- case3:(i’L,i’R)部分在L内,即 i’L < L < i’R < R,不用扩,O(1)
- case4: i’L == L,重合,i增长, O(n)
可见只有case1 和case4 需要扩,字符串长度为n,则为O(n)
代码实现
1 | // 慎用,string累加时在处理拷贝内存时耗时很大 |