为了表述方便,我们定义一个新概念臂长,表示中心扩展算法向外扩展的长度。如果一
个位置的最大回文字符串长度为 2 * length + 1
,其臂长为length
。
下面的讨论只涉及长度为奇数的回文字符串。长度为偶数的回文字符串我们将会在最后与长 度为奇数的情况统一起来。
在中心扩展算法的过程中,我们能够得出每个位置的臂长。那么当我们要得出以下一个位置
i
的臂长时,能不能利用之前得到的信息呢?
答案是肯定的。具体来说,如果位置 j
的臂长为 length
,并且有
j + length > i
,如下图所示:
当在位置 i
开始进行中心拓展时,我们可以先找到 i
关于 j 的对称点
2 * j - i
。那么如果点 2 * j - i
的臂长等于 n
,我们就可以知道,点 i
的臂
长至少为 min(j + length - i, n)
。那么我们就可以直接跳过 i
到
i + min(j + length - i, n)
这部分,从 i + min(j + length - i, n) + 1
开始拓
展。
我们只需要在中心扩展法的过程中记录右臂在最右边的回文字符串,将其中心作为 j
,在
计算过程中就能最大限度地避免重复计算。
那么现在还有一个问题:如何处理长度为偶数的回文字符串呢?
我们可以通过一个特别的操作将奇偶数的情况统一起来:我们向字符串的头尾以及每两个字
符中间添加一个特殊字符 #
,比如字符串 aaba
处理后会变成 #a#a#b#a#
。那么原先
长度为偶数的回文字符串 aa
会变成长度为奇数的回文字符串 #a#a#
,而长度为奇数的
回文字符串 aba
会变成长度仍然为奇数的回文字符串 #a#b#a#
,我们就不需要再考虑
长度为偶数的回文字符串了。
注意这里的特殊字符不需要是没有出现过的字母,我们可以使用任何一个字符来作为这个特 殊字符。这是因为,当我们只考虑长度为奇数的回文字符串时,每次我们比较的两个字符奇 偶性一定是相同的,所以原来字符串中的字符不会与插入的特殊字符互相比较,不会因此产 生问题。