Manacher算法
先来看这样一道题
最长回文子串
我们知道,这道题可以用后缀数组 O ( n l o g n ) O(nlogn) O(nlogn)的时间复杂度内求出
但是这题 1.1 ∗ 1 0 7 1.1 * 10 ^ 7 1.1∗107的范围明摆着是卡后缀数组的
虽说一般来说出题人不会这么丧心病狂,但是有时会需要统计例如以每一个字符为中心的最长回文串长度,这时使用后缀数组就会比较麻烦。幸运的是,还有一种非常简单的线性解法(甚至比后缀数组还好写)—— M a n a c h e r Manacher Manacher算法
Manacher算法的大体思想
其实很简单。
首先,我们将每两个字符间插入一个#。这样就能确保原串中的每个回文子串在新串中都对应着一个长度为奇数的回文子串。
在两侧插入两个未出现的字符防止溢出。
如果一个回文串长度 = len,定义它的回文半径 = ( l e n + 1 ) / 2 = (len + 1) / 2 =(len+1)/2
设 c n t i cnt_i cnti表示以 i i i为对称中心的最长回文子串的回文半径。
我们从左往右依次考虑,设当前考虑到第 i i i位
假设以 [ 1 , i − 1 ] [1, i - 1] [1,i−1]为对称中心的最长回文子串对称中心为 p o s pos pos, 最右边界为 m a x r maxr maxr。
显然有 c n t p o s + p o s = m a x r cnt_{pos} + pos = maxr cntpos+pos=maxr
当 m a x r < i maxr < i maxr<i时,我们直接从 i i i开始往两边暴力扩展并计算
否则,
我们先考虑 i + c n t i < = m a x r i + cnt_i <= maxr i+cnti<=maxr的情况, 即当前回文子串右边界不超过 m a x r maxr maxr的情况
考虑 i i i关于 p o s pos pos的对称点 i ′ i' i′
我们发现,此时的每一个回文子串都恰好对应着一个以 i ′ i' i′为对称中心的相等的回文子串
什么意思?就是当当前回文子串的右边界不超过 m a x r maxr maxr时,我们将它的每个点都关于 p o s pos pos对称,由于小回文串的对称性,我们得到的是一个以 i ′ i' i′为对称中心的回文子串,且这两个回文子串由于大回文串的对称性而相等
而我们发现以 i ′ i' i′为中心的回文串我们先前已经计算过了
于是我们在 c n t i ′ 和 m a x r − i cnt_{i'}和maxr - i cnti′和maxr−i之间取个小(因为要确保 i + c n t i < = m a x r i + cnt_i <= maxr i+cnti<=maxr),然后继续暴力匹配即可
复杂度保证:
m a x r maxr