KMP和Manacher算法
Manacher算法
- 预处理:统一奇偶长度
- 回文串有奇数长度(如”aba”)和偶数长度(如”abba”)之分,这会给统一处理带来麻烦。
- Manacher算法通过在原始字符串的每个字符之间以及首尾插入一个原字符串中不存在的特殊字符(通常用
#)来进行预处理。例如,"abba"会被处理成"#a#b#b#a#"。 - 这样做的好处是:无论原字符串如何,新字符串的长度总是奇数,所有回文子串都变成了奇数长度,从而可以统一以每个字符为中心进行扩展检查。
- 利用回文对称性
- 算法维护一个回文半径数组
P(也称为辅助数组),P[i]表示以新字符串中第i个字符为中心的最长回文子串的半径(包含中心字符本身)。例如,对于字符串"#a#b#a#",以中间的b(位于索引4)为中心,其回文半径是4。 - 关键在于,算法在从左至右遍历字符串时,会动态维护一个当前已知的最右回文边界
R以及达到该边界的中心位置C。 - 当遍历到位置
i时,如果i在当前最右边界R之内,则可以找到i关于中心C的对称点j。根据回文的对称性,可以利用P[j]的值来快速确定P[i]的一个初始最小值,从而避免从1开始逐个字符扩展,大大减少了比较次数。这通常归纳为几种情况:- 如果
j的回文区域完全包含在C的大回文区域内,那么P[i]直接等于P[j]。 - 如果
j的回文区域超出了C的大回文区域,那么P[i]至少为R - i。 - 如果
j的回文区域恰好到达C的大回文区域边界,则P[i]的初始值设为R - i,并需要继续向两侧扩展检查。
- 如果
- 如果
i超出了R,则无法利用对称性,只能进行朴素的中心扩展。 - 无论哪种情况,在获得初始值后,算法都会尝试继续向两侧扩展,以检查是否能得到更长的回文串,并相应地更新
R和C。
- 算法维护一个回文半径数组
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 岁迹!
