算法简介
Manacher 算法能够在线性时间内求出一个字符串的最长回文子串。
算法原理
记原字符串为 S,长度为 N。
在 S 中的任一对相邻字符间插入一个特殊字符**’$’**,目的是保证新串中所有的回文子串长度都为奇数。
设以 s[i] 为中心的最长回文串长度为 $2R[i]+1$。
那么,如果 $j < i$ 且 $j+R[j] > i$;作 $i$ 点关于 $j$ 的对称点 $i’$,则必有 $i’ > j-R[j]$。
见下图
在上图中,$i’-R[i’] > j-R[j’]$;由对称性,可以断言 $R[i]=R[i’]$。
事实上,假设 $k’=i’-R[i’]-1$ 关于 $j$ 的对称点为 $k$; $k$ 关于 $i$ 的对称点为 $k_i$;$k_i$ 关于 $j$ 的对称点为 $k’_i$ 。
由于 $S[k]=S[k’]$,$S[k_i]=S[k’_i]$;$S[k’] \neq S[k’_i]$。
所以 $S[k] \neq S[k_i]$,故 $R[i]=R[i’]$。
在上图中,$i’-R[i’] < j-R[j’]$;由对称性,可以断言 $R[i]=j+R[j]-i$。
当 $j+R[j] \leqslant i$ 时,不能做出更多的假设,只能暴力匹配。
幸运地是,可以证明暴力匹配的总字符数是 $O(N)$ 的。
算法实现
所谓的插入特殊字符是为了方便讲解,实现时可以将回文串 $[l,r]$ 的长度存在 $R[l+r]$ 中。
不难发现,当回文串长度为偶数时,$l+r \equiv 1\mod(2)$。
参考了《ACM国际大学生程序设计竞赛:算法与实现》的代码。
1 | void Manacher(char* S, int* R, int n) { |
复杂度分析
由于每一次只从未被匹配过的字符出发往右扩展,一共只有 $O(N)$ 个字符,所以复杂度是线性的。
空间复杂度
$O(N)$时间复杂度
$O(N)$
Hint
1 | if( i&1 ) len = R[i]*2; |
小记
第一次接触这个算法是在 2016 年武大的校赛上;
第一次没有抱大腿获奖;
虽然奖品有点坑。。。