Manacher 算法学习笔记
算法用处:
解决最长回文子串的问题(朴素型)。
算法复杂度
我们不妨先看看其他暴力解法的复杂度:
- \(O(n^3)\)
枚举子串的左右边界,然后再暴力判断是否回文,对答案取 \(max\) 。 - \(O(n^2)\)
枚举回文子串的对称轴,向两边扩展,对答案取 \(max\) 。 - \(O(n)\)
\(\texttt{Manacher}\) 算法。
显然我们的 \(\texttt{Manacher}\) 是十分优秀的。。。
实现原理
\(\text{step 1}\)
首先我们需解决一个问题:
回文串的长度有有奇也有偶,这会对我们的算法带来不利,如何解决?
我们可以对原串进行一些改造:
我们在原串的每两个字符之间都插入同一个字符(保证与原来串中的字符不重复)。
举个例子:
对于一个串:\(S = \texttt{"abbabaab"}\)
我们进行上述操作:\(S^\prime = \texttt{"/a/b/b/a/b/a/a/b/"}\)
我们把它变成这样,于是我们发现:
对于长度为奇数的回文串,它的回文中心是原串的字符;
对于长度为偶数的回文串,它的回文中心是加入的字符;
那么我们 \(S\) 中的任意一个回文子串都会在 \(S^\prime\) 中唯一对应一个字符。
于是我们可以开始在 \(S^\prime\) 上进行操作。
\(\text{step 2}\)
我们对于 \(S^\prime\) 中的每一个字符 \(S^\prime[i]\) 维护一个 \(f[i]\)
表示以 \(S^\prime[i]\) 为回文中心可以扩展的最远位置和 \(i\) 的下标之差(也就是这两点之间的距离)
我们只要求出了每一个位置的 \(f[i]\),那么该位置作为对称中心时的回文串的长度就是 \(f[i]\):
- 对于 \(S^\prime[i] \in S\),(比如
/q/w/q/
),显而易见。。。 - 对于 \(S^\prime[i] \notin S\),(比如
/y/y/
),这也是显而易见的。。。
于是我们考虑求出这个 \(f[i]\),答案就是 \(\max\limits_{1\leq i \leq N}\{f[i]\}\)
\(\text{step 3}\)
我们需要发现一个很重要的性质:
- 如果对于一个回文子串,其内部还有一个回文子串,
- 那么也必定会有一个与之全等的字串与它关于这个较大回文子串的对称中心对称
这个性质应该是显然的。。。
在整个算法进行过程中,我们记录一个 \(MaxRight\) 和一个 \(Mid\)
其中 \(MaxRight\) 表示我们扩展过的最远的位置,\(Mid\) 表示它对应的回文中心。
那么对于我们当前的 \(i\) :
- 若 \(i<MaxRight\) ,那么我们可以把 \(f[i]\) 初始化为 \(\min\{f[j], MaxRight-i\}\)
其中的 \(j\) 表示我们刚刚提到过的,该位置对称的那个点,
即以 \(i\) 为对称中心的回文子串与以 \(j\) 为对称中心的回文子串关于 \(Mid\) 对称。 - 若 \(i>MaxRight\) ,那么就不管。。。
然后,我们暴力的去扩展 \(f[i]\),并最终用固定下来的 \(i\) 和 \(f[i]\) 来更新 \(MaxRight\) 和 \(Mid\)。
这样就可以在 \(O(n)\) 时间内求出所有的 \(f[i]\) 了。(复杂度证明?我好像不会。。。)
模板题
Luogu
板子题不解释
/*--------------------------------
--Author: The Ace Bee-------------
--Blog: www.cnblogs.com/zsbzsb----
--This code is made by The Ace Bee
--------------------------------*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
#define clr(x, y) memset(x, y, sizeof x)
using namespace std;
template < typename T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= (c == '-'), c = getchar();
while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
s = f ? -s : s;
}
const int _(11000010);
int n, f[_ << 1];
char s[_ << 1], tmp[_];
inline int manacher() {
int n = strlen(s + 1);
for (rg int i = 1; i <= n; ++i) tmp[i] = s[i];
for (rg int i = 1, j = 0; i <= n; ++i) s[++j] = '`', s[++j] = tmp[i];
s[0] = s[n * 2 + 1] = '`', n = n * 2 + 1;
int mx = 0, mid;//mx 即 MaxRight,mid 即 Mid
for (rg int i = 1; i <= n; ++i) {
f[i] = i < mx ? min(mx - i, f[mid * 2 - i]) : 0;
while (s[i - f[i] - 1] == s[i + f[i] + 1]) ++f[i];
if (i + f[i] > mx) mx = i + f[i], mid = i;
}
int res = 0;
for (rg int i = 1; i <= n; ++i) res = max(res, f[i]);
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.in", "r", stdin);
#endif
scanf("%s", s + 1);
printf("%d\n", manacher());
return 0;
}
Manacher 算法学习笔记的更多相关文章
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Manacher算法学习笔记
前言 Manacher(也叫马拉车)是一种用于在线性时间内找出字符串中最长回文子串的算法 算法 一般的查找回文串的算法是枚举中心,然后往两侧拓展,看最多拓展出多远.最坏情况下$O(n^2)$ 然而Ma ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- Manacher算法学习 【马拉车】
好久没写算法学习博客了 比较懒,一直在刷水题 今天学一个用于回文串计算问题manacher算法[马拉车] 回文串 回文串:指的是以字符串中心为轴,两边字符关于该轴对称的字符串 ——例如abaaba 最 ...
- 算法学习笔记——sort 和 qsort 提供的快速排序
这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...
- manacher算法学习(求最长回文子串长度)
Manacher总结 我的代码 学习:yyb luogu题目模板 xzy的模板 #include<iostream> #include<cstdlib> #include< ...
随机推荐
- VS Code的git的使用方法
上一篇文章中记录了vscode中git的配置过程VS Code中配置git 这篇文章中记录下vscode中git的简单使用 vscode不是一个IDE没有新建工程的方法 我一般是在本地中新建一个工程文 ...
- 定位布局 Stack 层叠组件 Stack 与 Align Stack 与 Positioned 实现
一.Flutter Stack 组件 Stack 表示堆的意思,我们可以用 Stack 或者 Stack 结合 Align 或者 Stack 结合 Positiond 来实现页面的定位布局 align ...
- idea 快捷使用(一)条件断点的使用
调试的时候,在循环里增加条件判断,可以极大的提高效率,心情也能愉悦.以下介绍下IDEA使用条件[Condition]断点的方法 1.编写一段样例代码 /** * @author jiashubing ...
- IDEA部署项目,并结合Shell脚本运行Java程序
一.概述 在实际开发中,我们写好的代码,往往打成war包或jar包,通过winscp或其他软件将其上传至服务器,然而这样非常大的一个弊端就是不利于开发,为什么这么说呢?假如我们刚刚将springboo ...
- python练习:编写一个程序,要求用户输入一个整数,然后输出两个整数root和pwr,满足0<pwr<6,并且root**pwr等于用户输入的整数。如果不存在这样一对整数,则输入一条消息进行说明。
python练习:编写一个程序,要求用户输入一个整数,然后输出两个整数root和pwr,满足0<pwr<6,并且root**pwr等于用户输入的整数.如果不存在这样一对整数,则输入一条消息 ...
- js中ES6的Set的基本用法
ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. const s = new Set(); [2,3,5,4,5,2,2].forEach(x => s. ...
- Fluent_Python_Part3函数即对象,07-closure-decoration,闭包与装饰器
第7章 函数装饰器和闭包 装饰器用于在源码中"标记"函数,动态地增强函数的行为. 了解装饰器前提是理解闭包. 闭包除了在装饰器中有用以外,还是回调式编程和函数式编程风格的基础. 1 ...
- Wordpress-微信机器人高级版
微信机器人高级版是我爱水煮鱼开发的一款插件,功能很棒,运行此插件需要同时开启WPJAM Basic插件. 高级版5.0 版本对服务器要求非常高,只支持 Linux 服务器,PHP 要求 7.2 及以上 ...
- python:布尔类型
bool:有两个值,True 和 False bool 其实是int类型的一个子类,True一般为1,False一般为0 判断前一个是否是后一个的子类:issubclass(A, B) 内建函数boo ...
- 201771010135杨蓉庆 《面对对象程序设计(java)》第九周学习总结
第7章 异常.日志.断言和调试 1.实验目的与要求 (1) 掌握java异常处理技术: (2) 了解断言的用法: (3) 了解日志的用途: (4) 掌握程序基础调试技巧: 一.理论知识 1.异常:在程 ...