$Manacher$算法
例题:回文串
$Manacher$算法,又叫“马拉车”算法,只适用于在时间复杂度为$O(N)$的情况下求解一个字符串的最长回文子串长度的问题。
一、预处理
回文串长度个数为奇数,则其对称位置在某个字符。否则在两个字符中间,非常不利于计算回文串长度。
处理方法: 在字符串两边加 ‘#’ ,任意两个字符串之间加 ‘#’。
字符串新长度 $=$ 原长度 $\times$ 2 $+$ 1;(’#’ 个数始终比原字符个数多 1)。这样的处理保证了任意字符串都是奇数字符串。如果知道回文字符串的半径就可以求出字符串长度,也就可以求出原字符串长度。
原字符串长度 $=$ (字符串长度 $-$ 1)$/$ 2 $=$ (r $\times$ 2 $-$ 1 $-$ 1)$/$ 2 $=$ r $-$ 1。(假设该字符串就是回文串,因此字符串长度 = r $\times$ 2 $-$ 1,因此规定一个字符的回文串半径为 1)
关于 字符串长度 $=$ r $\times$ 2 $-$ 1 有如下示意。
1 | old_str: a b a |
二、算法过程
维护一个最靠右边的回文串 $(sl-sr)$,计算一个记录着以当前字符 $b[i]$ 为中心的回文串的半径 $p[i]$。每次计算有以下情形:
更新 $p[i]$ 时可以利用对称性:
1 | //i 在 mr 的内部: p[i] = min(p[j], mr - i) j为i的对称点 j = 2 * mid - i |
$p[i]$ 关于 最右回文串的对称字符串在 $(sl-sr)$ 范围内,那么 $p[i]$ = $p[j]$ ($j$ 为对称子串的中心)不在范围内,因为$(sl - sr)$ 是最右的回文串,所以 $p[i]$ 等于其对称子串在 $(sl-sr)$ 中的最大半径。(因为其对称子串范围超过了 $(sl-sr)$,且 $(sl-sr)$ 无法向右扩张,即 $str[sr + 1] != str[sl - 1]$。 那么此时 $p[i]$ 就等于其对称子串在$(sl-sr)$范围内的半径)
不可以利用对称性就暴力向外扩张的求 $p[i]$
1 | p[i] = 1; |
计算结束后,用本次 p[i] 更新 最靠右的回文子串。
1 | // 更新mr 和 mid |
三、图解
代码:
时间复杂度:$O(N)$
1 |
|