【算法】 马拉车Manacher算法(最长回文子串)(terse版)

​ 马拉车算法是用来求最长回文子串的,它充分了利用了回文串镜像对称相等的特征,每次维护最右边的回文串,分类讨论得出递推式。

第一步 平衡奇偶性

​ 回文串分为两大类:奇回文串 和 偶回文串。

​ 它们的半径有着不同的定义, 所以我们要统一对半径的定义。

​ 在字符串每两个字符中间加入一个特殊字符,再在一头一尾加入两个不同的特殊字符(避免越界)(保证不会与字符串中的字符重叠)。

​ 这样的话,就统一了回文串的奇偶性。

半径:回文串中心到边缘的距离(包括中心和边缘)。

第二步 分类讨论

​ 对于字符串s中的s[i], 已经算出了一个以C为中心的最右回文子串,它的左端点是l,右端点是r。

​ 那么,我们做i关于C的镜像对称点j。

​ 则分为两种情况:

​ 1、j <= l,这也意味着i >= r, 因为r右边的元素都没有检查过,所以并不能得到什么结论,用中心扩展法枚举。

​ 2、j > l,细分为两种情况。

​ 2.1:j的回文串被C的回文串包含,根据镜像对称的原理,i的回文串至少有p[j]的长度(p数组储存的是以i为中心的最长回文串的半径),至于是否有扩展,根据中心扩展法枚举。

​ 2.2:j的回文串超过了C的回文串,则镜像对称到i来,该串的右端点必定超过了r,但是因为r右边尚未检查,所以回文串初步设为C+p[C]-i,再进一步中心扩展。

​ 计算完后,每次更新C,l,r。

模板代码:

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
int p[6005], ans;
string s, g;
void Manacher() {
    int r = 0, c;
    for (int i = 0; i < g.size(); i++) {
        if (i < r)
            p[i] = min(p[2 * c - i], p[c] + c - i);
        else
            p[i] = 1;
        while (g[i + p[i]] == g[i - p[i]]) p[i]++;
        if (p[i] + i > r) {
            r = p[i] + i;
            c = i;
        }
    }
}
int main() {
    g += "$#";
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        g += s[i];
        if (i != s.size() - 1)
            g += '#';
    }
    g += "#&";
    Manacher();
    for (int i = 0; i < g.size(); i++) {
        ans = max(ans, p[i]);
    }
    cout << ans - 1;
}
相关推荐
tjl521314_215 分钟前
01C++ 分离编译与多文件编程
前端·c++·算法
_日拱一卒6 分钟前
LeetCode:23合并K个升序链表
java·数据结构·算法·leetcode·链表·职场和发展
哆啦刘小洋9 分钟前
【LeetCode每日一题】:2033(贪心+快速排序魔改)
算法·leetcode
WolfGang00732112 分钟前
代码随想录算法训练营 Day48 | 图论 part06
算法·图论
cheems952717 分钟前
[算法手记] 动态规划 ,二维费用限制背包问题如何处理
算法·动态规划
Chase_______23 分钟前
LeetCode 1343 题解:定长滑动窗口经典入门题,从暴力枚举到高效优化一文搞懂
算法·leetcode·职场和发展
样例过了就是过了24 分钟前
LeetCode热题100 单词拆分
c++·算法·leetcode·动态规划·哈希算法
王老师青少年编程38 分钟前
csp信奥赛C++高频考点专项训练之贪心算法 --【跳跃与过河问题】:跳跳!
c++·算法·贪心·csp·信奥赛·跳跃与过河问题·跳跳
MediaTea39 分钟前
ML:决策树的基本原理与实现
人工智能·算法·决策树·机器学习·数据挖掘
王老师青少年编程40 分钟前
csp信奥赛C++高频考点专项训练之贪心算法 --【跳跃与过河问题】:独木桥
c++·算法·贪心·csp·信奥赛·跳跃与过河问题·独木桥