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.首先对字符串进行预处理 因为回文分为奇回文和偶回文,分类处理比较麻烦,所 ...
随机推荐
- CSS002. 字体穿透蒙层(用img设置字体的color)
之前在逛Apple Store时看到了下面的UI: 交互图标非常圆滑上手也很舒服,虽然背景底色本就是白底,但是只依赖css能不能使 "+" 穿透背景看到底色 ? 大致思路如下: ...
- linux主机安全加固-个人经验
说明:我并没有一个系统的网络安全知识体系,随笔里面提到的内容是个人在从事运维行业这几年中总结出来的一点经验,仅供大家参考. 说到linux主机安全加固,我可以想到的就是三个方向吧,基线整改.访问控制和 ...
- MySQL查询之内连接,外连接查询场景的区别与不同
前言 我在写sql查询的时候,用的最多的就是where条件查询,这种查询也叫内连查询inner join,当然还有外连查询outer join,左外连接,右外连接查询,常用在多对多关系中,那他们区别和 ...
- 使用GitHub Pages + docsify快速搭建一个站点
话不多说,先看效果: https://bytesfly.github.io/blog 为什么需要一个站点 肯定有人会问,既然有类似 博客园 这样优秀的平台来写博客,为什么还需要自己搭建站点呢? 放在G ...
- java设计模式,工厂,代理模式等
javaEE设计模式: 工厂模式:主要分为三种模式: 定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行. 为什么要使用工厂模式: (1) 解耦 : ...
- PHP的switch和ifelse谁更快?
对于多个if条件判断的情况下,我们使用switch来代替ifelse对于代码来说会更加的清晰明了,那么他们的效率对比呢?从PHP手册中发现有人已经对比过了,自己也用他的代码进行了实验: $s = ti ...
- 5ucms的评论列表该怎么写
查看所有评论 <a href="{sys:plusurl}comment/?id={field:id}">查看所有评论</a> <linkhref=& ...
- CLion远程调试嵌入式开发板程序
CLion远程调试嵌入式开发板程序 目录 CLion远程调试嵌入式开发板程序 1. 目的 2. 前提条件 3. CLion设置 3.1 设置一个Deployment 3.2 上传需要的目录到目标板子 ...
- Centos7下thinkphp5.0环境配置
首先把yum源修改为阿里的yum源,如果没有安装wget,先安装一个.(如果有请蹦过) wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors ...
- P3649-[APIO2014]回文串【PAM】
正题 题目链接:https://www.luogu.com.cn/problem/P3649 题目大意 一个字符串,求最大的回文串长度×出现次数 解题思路 构建出\(\text{PAM}\)然后统计一 ...