Manacher(马拉车)
Able was I ere I saw Elba. ----Napoléon Bonaparte(拿破仑)
一、回文串&回文子串
这个很好理解。
如果一个字符串正着读和反着读是一样的,那它就是回文串。 eg. abba ;
如果一个字符串 S 的子串 SS 为回文串,那么 SS 即为 S 的回文子串;若 SSS 为 S 的回文子串中最长的一个,那么我们称 SSS 为 S 的最长回文子串。
二、Manacher算法
如何找到一个字符串的最长回文子串呢?
我们很容易想到一个 O(n2) 的方法,即:从每个字符开始向两边爆搜。但显然,这个方法效率太低下了。
如何快速求出答案,这就是 Manacher算法的事了。
Ⅰ. 奇回文&偶回文
字面意思,不再赘述。
如果同时存在奇回文和偶回文,那么处理起来会比较的繁琐,下面就是Manacher 一个很巧妙的方法了:在字符串收尾,即各字符间插入一个特殊的字符(指没有出现过的字符),例如:
aba ----> #a#b#a#
abba ----> #a#b#b#a#
这样,所有的回文串就都成奇回文了。

inline int Pre()
{
S[0]='@',S[1]='#';
int j(1);
for(register int i=0,len=IP.size();i<len;++i) S[++j]=IP[i],S[++j]='#';
S[++j]='\0';return j;
}
预处理
Ⅱ. 最长回文半径
令一个回文串中最左或最右位置的字符与其对称轴的距离称为 " 回文半径 ",令 R [ i ] 表示字符 i 的最长回文半径。
| i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| S | @ | a | # | b | # | b | # | a | # | b | $ |
| R[i] | 边界 | 1 | 1 | 2 | 4 | 2 | 1 | 4 | 1 | 2 | 边界 |
显然,R [ i ] - 1 即为以 i 为中心的最长回文子串的长度。
那么,我们要求的最长回文子串,就成了 max { R [ i ] - 1 } 。
如何快速求出 R [ ] ???
Ⅲ. Manacher
从左往右依次讨论。
设 Max 为已讨论的子串中能达到的右端最大位置,P 为提供当前 Max 的字符位置。如下表:
| i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| Max的对称点 | P | Max |
接下来讨论的位置 i 可以分为两种情况:小于等于 Max ,大于 Max:
1. 小于等于 Max :
| i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| Max的对称点 | j(i的对称点) | P | i | Max |
由于 i 和 j 对称 ,所以求出 i 的对称点 j ,简直是 "轻易而举" 。
不难发现现在有可以分为两种情况讨论:
( 1 ) . 以 j 为对称轴的回文串比较短:那么可以直接令 R [ i ] = R [ j ] ;
( 2 ) . 以 j 为对称轴的回文串比较长:此时,我们只能确定不超过 Max 的部分的情况,对于 Max 以外的,我们需要以 i 为中心开始往两侧拓展,直到两侧不同,同时更新 p 和 Max。
2. 大于 Max : 这种情况很好处理,直接拓展就可以了(当然,要同时更新 p 和 Max)
Ⅳ. 代码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
char S[50000005];
int m,R[50000005];
string IP;
inline int Pre()
{
S[0]='@',S[1]='#';
int j(1);
for(register int i=0,len=IP.size();i<len;++i) S[++j]=IP[i],S[++j]='#';
S[++j]='\0';return j;
}
inline int Manacher()
{
m=Pre();
int RET(-1),x(0),Max(0);
for(register int i=1;i<m;++i)
{
if(i<Max) R[i]=min(R[2*x-i],Max-i+1);
else R[i]=1;
while(S[i-R[i]]==S[i+R[i]]) ++R[i];
if(Max<i+R[i]-1) x=i,Max=i+R[i]-1;
RET=max(RET,R[i]-1);
}
return RET;
}
int main()
{
ios::sync_with_stdio(false);
cin>>IP,cout<<Manacher();
return 0;
}
Manacher
Ⅴ. 时间复杂度
由于Max是不断向右拓展的,最多拓展 n 次,不难得出 马拉车 的时间复杂度是线性的,即 O( n )。
Manacher(马拉车)的更多相关文章
- Manacher(马拉车)算法(jekyll迁移)
layout: post title: Manacher(马拉车)算法 date: 2019-09-07 author: xiepl1997 cover: 'assets/img/manacher.p ...
- manacher(马拉车算法)
Manacher(马拉车算法) 序言 mannacher 是一种在 O(n)时间内求出最长回文串的算法 我们用暴力求解最长回文串长度的时间复杂度为O(n3) 很明显,这个时间复杂度我们接受不了,这时候 ...
- HDU - 3068 最长回文manacher马拉车算法
# a # b # b # a # 当我们遇到回判断最长回文字符串问题的时候,若果用暴力的方法来做,就是在字符串中间添加 #,然后遍历每一个字符,找到最长的回文字符串.那么马拉车算法就是在这个基础上进 ...
- Manacher (马拉车) 算法:解决最长回文子串的利器
最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...
- Manacher马拉车
俗话说:摩托再好,不如骡拉啊(好像不是骡) Manacher就是O(N)计算最长回文子串的算法. 其中我们需要在0位置加入字符“$",然后原字符串中每两个字符加入一个"#" ...
- manacher马拉车算法
Manacher算法讲解 总有人喜欢搞事情,出字符串的题,直接卡掉了我的40分 I.适用范围 manacher算法解决的是字符串最长回文子串长度的问题. 关键词:最长 回文 子串 II.算法 1.纯暴 ...
- 最长回文子串 —— Manacher (马拉车) 算法
最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...
- manacher/马拉车常用用法一览
因为manacher算法把原来的字符串扩大了两倍,因此在应用时许多二级结论都非常不直观,现场推出来很麻烦,因此笔者在此做个简单整理,如果发现有错误或者有常用的我没有涉及到的,恳请在下方评论区指出,我会 ...
- Manacher(马拉车)算法
Manacher算法是一个求字符串的最长回文子串一种非常高效的方法,其时间复杂度为O(n).下面分析以下其实行原理及代码: 1.首先对字符串进行预处理 因为回文分为奇回文和偶回文,分类处理比较麻烦,所 ...
随机推荐
- word文档转成图片
1:先把word文档转成pdf格式 这个是在word中转成pdf格式,保存好 2:再把pdf格式转成图片 在这个链接中打开https://smallpdf.com/cn/pdf-converter, ...
- [第十五篇]——Swarm 集群管理之Spring Cloud直播商城 b2b2c电子商务技术总结
Swarm 集群管理 简介 Docker Swarm 是 Docker 的集群管理工具.它将 Docker 主机池转变为单个虚拟 Docker 主机. Docker Swarm 提供了标准的 Dock ...
- 手动制作Docker镜像
手动制作 Docker 镜像 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器(用来用去感觉 Windows 的 Docker 出各种问题,比如使用 ...
- 【PHP数据结构】图的存储结构
图的概念介绍得差不多了,大家可以消化消化再继续学习后面的内容.如果没有什么问题的话,我们就继续学习接下来的内容.当然,这还不是最麻烦的地方,因为今天我们只是介绍图的存储结构而已. 图的顺序存储结构:邻 ...
- webpack learn1-初始化项目1
使用Visual Studio Code软件使用准备,先安装一些插件,加快开发效率(还有Language Packs 选择简体中文安装后重启软件,可切换为中文): 下面是项目初始化步骤: 1 软件打 ...
- html5 sessionStorage util
/** * Created by 13352 on 2018/7/5. */ define(function() { var session = { _id: null, _cookieCache ...
- 《DotNet Web应用单文件部署系列》三、混淆dll文件
众所周知,C#编译后的dll文件可被反编译,网上搜索"C# 反编译"会出现一大堆资料.为了提高反编译成本,我们必须对dll文件进行混淆处理. 目前,C#混淆工具很多,我推荐obfu ...
- 关于java中BigDecimal的简介
关于java中BigDecimal的简介 1.BigDecimal属于大数据,精度极高,不属于基本数据类型,属于java对象(引用数据类型), 这是sun提供的一个类,专门用在财务软件中. 2.注意: ...
- 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 百篇博客分析OpenHarmony源码 | v67.01
百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
- P5748-集合划分计数【EGF,多项式exp】
正题 题目链接:https://www.luogu.com.cn/problem/P5748 题目大意 求将\(n\)的排列分成若干个无序非空集合的方案. 输出答案对\(998244353\)取模. ...