Manacher算法

形象的被译为马拉车算法

这个算法用于处理简单的回文字符串的问题。可以在 \(O(n)\) 的复杂度内处理出每一个位置为中心的回文串的最长长度。

为了避免出现偶数长度的回文串,导致过多的分类讨论,我们预处理一下字符串。

例如:jeefy

我们可以预处理成 ^#j#e#e#f#y#$。(开始,间隔和结束符尽量不一样,并且不能出现在原序列中)

那么我们再定义一点点东西:

  • P[i] 指在处理后的字符串中,以 i 为中心的回文串的最大长度的半径(包括了 i)也就是说,处理后的串中,(i-P[i], i+P[i]) 这个开区间是一个回文串。

  • R 指我们已经搜索到的最右边界,M 指最右边界对应的中心

为了方便讲解,我们先考虑更朴素的算法:中心扩展法(名字来源LeetCode)。

其实思路很简单,我们以某一个点为中心向两边扩展,同时需要分类讨论奇数长度和偶数长度。

int expandAt(char * s, int l, int r) {
int len = strlen(s);
while (0 <= l && r < len && s[l - 1] == s[r + 1]) ++r, --l;
return r - l - 1;
}

未验证代码,注意甄别

其时间复杂度为 \(O(n^2)\) ,但是,在随机数据下,其表现接近于线性。毒瘤出题人当然不愿意了

所以,有了 Manacher 算法来优化。

其算法核心思想在于利用回文串的对称性,这样我们可以充分的利用其对称区间的信息。

如图:

若黑色区间是一个回文串,且黑色竖线为其中心已知红色区间是一个能向外扩展的最长回文串,那么很容易得知橙色的区间也是一个回文串,并且这个回文串对于这个中心是最长的

理解回文串的对称性,如果橙色的不是最长的,意味着对称过来红色的也不是最长的,与已知冲突。

那么我们考虑什么时候可以扩展出去?

如图,如果左侧对应的回文串左边界超过或者等于黑色部分的边界,那么,实际上,右侧只有橙色部分(黑色边界内)的信息是可以用的。

因为回文串的对称性并没有包括了黑色部分以外的信息,所以……

同理,如果右侧的中心已经在黑色部分以外了……那么也没有可用的信息,暴力扩展即可。

参考代码:

for (int i(1); i < n; ++i) {
p = R > i ? min(R - i + 1, P[(M<<1) - i]) : 1; // 可用信息
while (s[i + p] == s[i - p]) ++p; // 向两边扩展
if (i + p - 1 > R) M = i, R = i + p - 1; // 更新边界
P[i] = p;
}

复杂度证明:

我们考虑边界 R,从 0 更新到 n,总共变化了 n 次。

那么 R 什么时候被更新?

也就是第二种情况,可以向外扩展才可以更新 R,且每一次成功的扩展会使 R 变大一位。

如果是第一种情况,那么是无法向外扩展的,且 R 也不会改变。

也就是说,最多只会扩展 \(O(n)\) 次,所以,整个算法的复杂度为 \(O(n)\),常数非常小。


对于模板题:【模板】manacher 算法 - 洛谷

参考代码如下:


例题:SHOI2011 双倍回文

可以参考我的题解:[SHOI2011]双倍回文 题解 - jeefy - 博客园


那么 Mancher 是否只能用在字符串上?

可以发现的是 Manacher 算法其实和字符集的大小没有关系,并且只用到了相等与不等的关系。

这启发我们其实完全可以扩展 Manacher 的,处理更多的信息。

经典的一道题是:CF1080E,其中定义的是字符的集合的相等和不等关系,也就是从字符扩展到了字符的集合。这也可以通过哈希来判断,也就是扩展到整数上。

算法学习笔记(13): Manacher算法的更多相关文章

  1. 【学习笔记】Manacher算法

    本文部分图片来源 代码来源(代码是学姐哒.. 一.引入 Manacher算法是用来求最长回文子串的算法,时间复杂度O(n). 回文子串指的是''aacaa'',''noon'',这种正着反着读都一样的 ...

  2. 【算法学习笔记】Meissel-Lehmer 算法 (亚线性时间找出素数个数)

    「Meissel-Lehmer 算法」是一种能在亚线性时间复杂度内求出 \(1\sim n\) 内质数个数的一种算法. 在看素数相关论文时发现了这个算法,论文链接:Here. 算法的细节来自 OI w ...

  3. 算法学习笔记:Kosaraju算法

    Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起的算法,它的发明人是S. Rao Kosaraju,这是一个在图论当中非常著名的算法,可以用来拆分有向图当中的强连通分量. 背景知识 ...

  4. 算法学习笔记:Tarjan算法

    在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实现.今天介绍的算法名叫Tarjan,同样是一个很奇怪的名字,奇怪就对了,这也是以 ...

  5. Miller-Rabin 与 Pollard-Rho 算法学习笔记

    前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...

  6. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  7. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  8. 算法学习笔记(5): 最近公共祖先(LCA)

    最近公共祖先(LCA) 目录 最近公共祖先(LCA) 定义 求法 方法一:树上倍增 朴素算法 复杂度分析 方法二:dfs序与ST表 初始化与查询 复杂度分析 方法三:树链剖分 DFS序 性质 重链 重 ...

  9. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  10. GMM高斯混合模型学习笔记(EM算法求解)

    提出混合模型主要是为了能更好地近似一些较复杂的样本分布,通过不断添加component个数,能够随意地逼近不论什么连续的概率分布.所以我们觉得不论什么样本分布都能够用混合模型来建模.由于高斯函数具有一 ...

随机推荐

  1. 顺通鞋业MES生产工单管理系统软件

    顺通鞋业MES管理系统的"生产执行"是办公室和车间信息交互的枢纽,是一款针对大型鞋业生产企业开发的可配置化智能制造管理系统.工人可以通过车间终端(如安装在机器旁的固定工业触摸屏或移 ...

  2. vscode设置语法错误时在文件名显示报错

  3. DDD领域驱动设计总结和C#代码示例

    DDD(领域驱动设计)是一种软件设计方法,它强调以业务领域为核心来驱动软件的设计和开发. DDD 的设计初衷是为了解决复杂业务领域的设计和开发问题,它提供了一套丰富的概念和模式,帮助开发者更好地理解和 ...

  4. Alibaba Cloud Linux 2 LTS 正式发布,提供更高性能和更多保障

    Alibaba Cloud Linux 2 LTS版本发布后,阿里云将会为该版本提供长达5年的软件维护.问题修复服务.从2019-03-27开始到2024-03-31结束.包括: 免费的服务和支持:A ...

  5. KubeVela 成为 CNCF 沙箱项目,让云端应用交付更加简单

    简介: KubeVela 就是这样一个面向用户的上层平台项目.对于业务开发者来说,KubeVela 简单.易用,它可以让开发者以极低的心智负担和上手成本在 Kubernetes 上定义与部署应用... ...

  6. [Trading] 股票日内交易者能赚多少钱 - 看到日内交易的潜力并学习如何实现它

    无论是为了生活方式.寻求刺激还是为了挑战,股票市场短线交易者能赚多少钱的问题不可避免地出现了. 股票日内交易者的交易量变化很大,一些当日交易者损失了他们的资金,而另一些人利用他们的资金创造了一个高的月 ...

  7. 基于EPCLYPS的DDS控制器(二)

    关于ZmodAWGController ZmodAWGController 介绍 双击IP核,进入的第一个界面会有Ch1 Gain Static Configuration的选项修改为 "0 ...

  8. 6.Ingress 七层负载

    官方文档:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/题目: 设置配置环境: [candidate@no ...

  9. pandas:时间序列数据的周期转换

    时间序列数据是数据分析中经常遇到的类型,为了更多的挖掘出数据内部的信息,我们常常依据原始数据中的时间周期,将其转换成不同跨度的周期,然后再看数据是否会在新的周期上产生新的特性. 下面以模拟的K线数据为 ...

  10. Competition Set - Codeforces

    这里记录的是这个账号的比赛情况. Codeforces Round 942 (Div. 1) Solved:6/8,AB1B2CDE1 2645-> A 题意:现有 \(a_i\) 张写有 \( ...