Manacher 算法(回文串)

问题

求字符串 的最长回文子串,时间复杂度

核心思想

利用回文的对称性,避免重复计算。维护当前已知的最右回文边界 及其中心

!
上图展示了以某个中心扩展回文的过程

!
利用对称性快速确定回文半径

!
当对称点半径触及右边界时,仍需中心扩展

算法步骤

  1. 字符串预处理: 在字符间插入分隔符 #,将奇偶长度的回文统一处理
原始: a b a b c
预处理: # a # b # a # b # c #

预处理后,所有回文串的长度都是奇数, 表示以 为中心的回文半径。

  1. 递推计算 :
  • 如果 在已知最右回文边界 内,利用对称点 初始化
  • 否则
  • 向两边扩展,直到不匹配
  • 如果 ,更新
vector<int> manacher(const string &s) {
 // 预处理
 string t = "#";
 for (char c : s) {
 t += c; t += '#';
 }
 int n = t.size();
 vector<int> d(n);
 int c = 0, r = 0;
 for (int i = 0; i < n; i++) {
 int mir = 2 * c - i; // 对称点
 if (i < r)
 d[i] = min(d[mir], r - i);
 while (i - d[i] >= 0 && i + d[i] < n
 && t[i - d[i]] == t[i + d[i]])
 d[i]++;
 if (i + d[i] > r) {
 c = i;
 r = i + d[i];
 }
 }
 return d;
}

表示扩展半径(包含中心自身),原始字符串中的回文长度为

重要性质

  • 是以 为中心的最长回文子串长度(在原始字符串中)
  • 算法过程中每个字符最多被扩展一次,因此时间复杂度为

推荐练习题

平台编号名称说明
洛谷P3805【模板】manacher最长回文子串
洛谷P1659拉拉队排练回文长度计数
洛谷P4555最长双回文串回文组合
LeetCode5Longest Palindromic Substring最长回文子串
LeetCode647Palindromic Substrings回文子串计数

相关链接

内容来源:经本地化改造的 OI-wiki Manacher 章节。详细推导见 OI-wiki

多平台练习

| 洛谷 | 本题单 | 竞赛基础 |
| POJ (北大) | PKU JudgeOnline | 经典题目,适合巩固 |
| HDU (杭电) | HDU OJ | 暑期多校训练 |
| Codeforces | Codeforces | 国际竞赛,适合提升 |