“先用Manacher 算法求 odd、even,再按中心查半径。下面的 函数由该页提供,完整下载脚本包含所有定义,可独立运行。”
逐个中心向两侧扩张,很容易写对回文程序。但在 aaaa…a 上,相同字符会被许多中心反复比较,总时间达到二次方。Manacher 的关键是保存一个已证实的大回文,让内部中心从对称位置借用已完成的工作;借到边界时停下,只有边界外仍需比较。
形式陈述
输入、输出与区间约定
输入是长度
两次扫描分别处理奇、偶中心。各自维护已处理中心中右端最远的回文区间
可直接运行的两个扫描
def manacher(s):
n = len(s)
odd, even = [0] * n, [0] * n
left = right = 0
for i in range(n):
k = 1 if i >= right else min(odd[left + right - 1 - i], right - i)
while i - k >= 0 and i + k < n and s[i - k] == s[i + k]:
k += 1
odd[i] = k
if i + k > right:
left, right = i - k + 1, i + k
left = right = 0
for i in range(n):
k = 0 if i >= right else min(even[left + right - i], right - i)
while i - k - 1 >= 0 and i + k < n and s[i - k - 1] == s[i + k]:
k += 1
even[i] = k
if i + k > right:
left, right = i - k, i + k
return odd, even
第二遍必须重新令 left=right=0:奇回文不能充当偶回文扫描的已证实外壳。本实现不用插入分隔符或哨兵,因此不要求在输入字母表之外另找字符。每个边界检查都发生在字符访问之前。
直觉
镜像信息究竟能借多少
先看奇中心。已知
若 odd[j] 小于
若 odd[j]≥
偶中心的论证相同,但反射的是间隙。外壳
为什么更新区间保持正确
把循环不变量写成三件事:所有小于
最大右端相同而不替换旧区间也正确,不要求
例子与边界
复算一个镜像不足以决定答案的位置
取 abacdcabba。奇扫描到 d 时,初始半径一;依次比较位置 c/c、a/a、b/b,得到半径四;再比较 a/b 失败。保存外壳 bacdcab。
处理 a/b,因此半径停在一;若直接复制二就会错误报告 abb 为回文。
偶扫描到间隙 b/b,再比较 a/a,得到 even[8]=2,区间 abba。下一圈右端越界而停止,不是字符失配。最后数组与回文半径页的表逐项一致,总出现数十六。
看起来小的下标偏差会漏掉整类输入
aa 的偶数组应为 ab 必须得到 even=[0,0],不能因初始化就承认长二回文。
算法按字符相等工作,不用字典序;把字符换成可常数时间比较的整数仍可使用。若比较本身要扫描可变长对象,总复杂度应改为字符比较次数乘相应代价。文本追加字符后,旧中心的最终半径还可能增长;本页函数处理一份固定全文,不能把已返回数组当作追加后仍自动正确的索引。
推论与应用
成功比较与失败比较分别记账
用摊还分析核算一次扫描。镜像半径严格落在外壳内时,下一次比较若发生便是已知失配,没有成功扩张。其余情况下,每次新成功比较都让当前回文的右端越过原来的最远边界一格;全程右边界只向右移动,故这类成功比较合计至多
失败字符比较不推动边界,却每个中心至多一次,因为一次失败就结束当前 while。边界越界同样终止循环,不会再读字符。于是每遍最多线性次成功比较、线性次失败比较及线性次初始化,两遍总计
从数组交付可核验结果
计算最长回文、回文出现总数或单区间查询,都可直接使用半径页公式。对 abacdcabba,应交付两份十项数组、出现数十六、最长区间
本单元核验程序把两份数组导出的每个区间判断与逐字符反转 oracle 对照,并检查空串、单字符、奇偶混合、全相同字符及 Unicode 码点输入。迁移练习用 bbaabbaabbaa:奇半径全为一,偶半径为
参考资料
- Glenn K. Manacher, “A New Linear-Time ‘On-Line’ Algorithm for Finding the Smallest Initial Palindrome of a String”, Journal of the ACM 22(3), 1975, pp. 346–351,DOI。原论文标题对应初始回文问题,本文呈现现代的全中心半径形式。
- Gabriele Fici, Travis Gagie, Juha Kärkkäinen and Dominik Kempa, A Subquadratic Algorithm for Minimum Palindromic Factorization, 2014,§1:从原算法到最大中心回文线性表示的文献脉络。
- KTH Competitive Programming, KACTL: Manacher.h:另一份奇偶半径实现。其奇半径不计中心、索引约定与本文不同,不能逐项照搬结果;本文代码按半开区间独立组织。