算法用处:

解决最长回文子串的问题(朴素型)。


算法复杂度

我们不妨先看看其他暴力解法的复杂度:

  • \(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 算法学习笔记的更多相关文章

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

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

  2. Manacher算法学习笔记

    前言 Manacher(也叫马拉车)是一种用于在线性时间内找出字符串中最长回文子串的算法 算法 一般的查找回文串的算法是枚举中心,然后往两侧拓展,看最多拓展出多远.最坏情况下$O(n^2)$ 然而Ma ...

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

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

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

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

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

  7. Manacher算法学习 【马拉车】

    好久没写算法学习博客了 比较懒,一直在刷水题 今天学一个用于回文串计算问题manacher算法[马拉车] 回文串 回文串:指的是以字符串中心为轴,两边字符关于该轴对称的字符串 ——例如abaaba 最 ...

  8. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

  9. manacher算法学习(求最长回文子串长度)

    Manacher总结 我的代码 学习:yyb luogu题目模板 xzy的模板 #include<iostream> #include<cstdlib> #include< ...

随机推荐

  1. 在linux环境下python与C++混合编程

    参考:在linux环境下编译C++ 程序 linux下python3调用c代码或者python3调用c++代码 https://blog.csdn.net/u013179327/article/det ...

  2. PL2303HXA自2012已停产

    解决"PL2303HXA自2012已停产,请联系供货商" USB不识别的问题: 问题是WIN10自带的驱动不兼容引起的,只能安装早期驱动,再驱动程序中选择旧版本驱动即可

  3. 【JavaScript基础#2】

    " 目录 #. 函数 1. 定义 2. arguments 参数 3. 全局变量与局部变量 4. 语法分析 #. 内置对象和方法 1. 自定义对象 2. 类之继承 3. Date 4. JS ...

  4. centos7 安装pip2和pip3

    linux pip2 安装cd /usr/bin yum install -y epel-release yum install -y python-pip _____________________ ...

  5. Spring Boot 使用 CXF 调用 WebService 服务

    上一张我们讲到 Spring Boot 开发 WebService 服务,本章研究基于 CXF 调用 WebService.另外本来想写一篇 xfire 作为 client 端来调用 webservi ...

  6. 吴裕雄 python 神经网络——TensorFlow 图像处理函数

    import numpy as np import tensorflow as tf import matplotlib.pyplot as plt image_raw_data = tf.gfile ...

  7. UNL/EVE关联putty和wireshark

    这里默认UNL已经安装完毕,然后启动虚拟机启动UNL. 在浏览器输入http://192.168.1.199/ 进入UNL.然后简单的搭建一个拓扑: 这里只讲R1和ASA开启,先来配置Telnet功能 ...

  8. 关于调用接口 Connection reset 问题(使用代理调接口)

    之前调用过别的公司的接口上传数据,但是遇到个问题就是Connection reset,查阅了网上的各种资料,说什么的都有,主要意思就是说发布接口和调用接口的某些配置不一样,但是这个怎么说呢,单方面没办 ...

  9. 什么是SOA架构

    什么是SOA架构 SOA是Service-Oriented Architecture的首字母简称,它是一种支持面向服务的架构样式.从服务.基于服务开发和服务的结果来看,面向服务是一种思考方式.其实SO ...

  10. Failed to read candidate component class

    今天编程时遇到了Failed to read candidate component class 这个异常,查了好久终于发现了是因为jdk的版本不对,所以报了这个错.