Manacher 算法(回文串)

问题

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

核心思想

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

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

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

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

算法步骤

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

    原始:    a  b  a  b  c
    预处理:  # a # b # a # b # c #
    

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

  2. 递推计算 :

    • 如果 在已知最右回文边界 内,利用对称点 初始化
    • 否则
    • 向两边扩展,直到不匹配
    • 如果 ,更新
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 | 国际竞赛,适合提升 |