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.首先对字符串进行预处理 因为回文分为奇回文和偶回文,分类处理比较麻烦,所 ...
随机推荐
- ASP.NET Core Web API 教程 - Project Configuration
ASP.NET Core Web API 教程 本系列文章主要参考了<Ultimate ASP.NET Core 3 Web API>一书,我对原文进行了翻译,同时适当删减.修改了一部分内 ...
- Mac下Sublime Text3配置Python开发环境
设置Sublime Text的语法为python View -> syntax ->python 设置编译环境(默认python版本2.7) Tools -> Build Syste ...
- Math.round真的是四舍五入吗?我不这么认为
public static long round(double a) 返回最接近参数的 long.结果将舍入为整数:加上 1/2,对结果调用 floor 并将所得结果强制转换为 long 类型.换句话 ...
- java原码反码补码以及位运算
原码, 反码, 补码的基础概念和计算方法. 对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式. 1. 原码 原码就是符号位加上真值的绝对值, 即 ...
- python matplotlib.pyplot 条形图详解
python matplotlib.pyplot 条形图详解 一.创建直方图 可以用bar函数来创建直方图 然后用show函数显示直方图 比如: import matplotlib.pyplot as ...
- 开源的物联网技术平台(Thingsboard)
1 总体说明 1.1 产品概述 1.1.1 Thingsboard作用 1.置备并控制设备. 2.采集设备数据并进行数据可视化. 3.分析设备数据,触发告警. 4.将数据传输到另一个系统. 5 ...
- 远程线程注入突破SESSION 0
远程线程注入突破SESSION 0 SESSION 0 隔离 在Windows XP.Windows Server 2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Se ...
- mysql操作中卡死 解决方法
1.使用指令查询当前进程 show full processlist; -- 查询全部当前进程; show processlist;-- 只列出前100条 2.找出卡死的进程id 3.删除卡死进程 k ...
- Orchar Core 创建一个模块化的ASP.NET Core应用程序
您将构建什么?您将构建一个模块化的ASP.NET Core MVC Web应用程序,类似于Orchard Core附带的示例"Hello World"应用程序.它包括一个Web应用 ...
- 怎么通俗的理解Netty呢?
目录 Netty(3.X) 简单体验 Netty的事件驱动机制 Netty的源码阅读 Netty(3.X) 有了Netty,你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,W ...