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< ...
随机推荐
- Bugku-CTF加密篇之贝斯家族(@iH<,{bdR2H;i6*Tm,Wx2izpx2!)
贝斯家族 @iH<,{bdR2H;i6*Tm,Wx2izpx2!
- C语言与汇编的嵌入式编程:求100以内素数
写汇编之前,需要搞清楚C语言代码的写法,这里以最简单的算法举例说明 C代码如下: #include <stdio.h> void main(){ int i,j; ; ;i<=;i+ ...
- dp饭卡
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够).所以大家 ...
- Java方法的定义和使用
/* 定义一个方法的格式: public static void 方法名称() { 方法体 } 方法名称的命名规则和变量一样,使用小驼峰. 方法体:也就是大括号当中可以包含任意条语句. 注意事项: 1 ...
- 基于SILVACO ATLAS的a-IGZO薄膜晶体管二维器件仿真(05)
关于特性曲线的输出调整: 初代版本 material material=igzo eg300=3.5 nc300=8.5e21 nv300=8.5e21 taun0=1e-9 taup0=1e-9 a ...
- python正则表达式中括号的作用,形如 "(\w+)\s+\w+"
先看一个例子: import re string="abcdefg acbdgef abcdgfe cadbgfe" #带括号与不带括号的区别 regex=re.compile(& ...
- 《JavaScript高级程序设计》读书笔记(三)基本概念第五小节流程控制语句
内容---语法 ---数据类型 上一小节---流程控制语句 本小节---理解函数 语句--ECMA-262规定了一组语句,也称流程控制语句 if语句-- 条件可以是任意表达式,-- ECMAScrip ...
- 工具 - 正则Cheat sheet
- Pychram 运行程序在 run 窗口和 python console 窗口之间切换
有图有真相 第一步: 第二步:
- Linux重装为Windows后读取原EXT类型数据盘
Linux重装为Windows后读取原EXT类型数据盘 1 2 3 4 分步阅读 Windows的文件系统通常使用NTFS或者FAT32格式,而Linux的文件系统格式通常是EXT系列.当操作系统从L ...