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的对称点                  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的对称点)       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(马拉车)的更多相关文章

  1. Manacher(马拉车)算法(jekyll迁移)

    layout: post title: Manacher(马拉车)算法 date: 2019-09-07 author: xiepl1997 cover: 'assets/img/manacher.p ...

  2. manacher(马拉车算法)

    Manacher(马拉车算法) 序言 mannacher 是一种在 O(n)时间内求出最长回文串的算法 我们用暴力求解最长回文串长度的时间复杂度为O(n3) 很明显,这个时间复杂度我们接受不了,这时候 ...

  3. HDU - 3068 最长回文manacher马拉车算法

    # a # b # b # a # 当我们遇到回判断最长回文字符串问题的时候,若果用暴力的方法来做,就是在字符串中间添加 #,然后遍历每一个字符,找到最长的回文字符串.那么马拉车算法就是在这个基础上进 ...

  4. Manacher (马拉车) 算法:解决最长回文子串的利器

    最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...

  5. Manacher马拉车

    俗话说:摩托再好,不如骡拉啊(好像不是骡) Manacher就是O(N)计算最长回文子串的算法. 其中我们需要在0位置加入字符“$",然后原字符串中每两个字符加入一个"#" ...

  6. manacher马拉车算法

    Manacher算法讲解 总有人喜欢搞事情,出字符串的题,直接卡掉了我的40分 I.适用范围 manacher算法解决的是字符串最长回文子串长度的问题. 关键词:最长 回文 子串 II.算法 1.纯暴 ...

  7. 最长回文子串 —— Manacher (马拉车) 算法

    最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...

  8. manacher/马拉车常用用法一览

    因为manacher算法把原来的字符串扩大了两倍,因此在应用时许多二级结论都非常不直观,现场推出来很麻烦,因此笔者在此做个简单整理,如果发现有错误或者有常用的我没有涉及到的,恳请在下方评论区指出,我会 ...

  9. Manacher(马拉车)算法

    Manacher算法是一个求字符串的最长回文子串一种非常高效的方法,其时间复杂度为O(n).下面分析以下其实行原理及代码: 1.首先对字符串进行预处理 因为回文分为奇回文和偶回文,分类处理比较麻烦,所 ...

随机推荐

  1. 使用Redis Stream来做消息队列和在Asp.Net Core中的实现

    写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消息队列,而不想引入新的服务,kafk ...

  2. electron-vue 开发问题合集

    (一)Found 'electron' but not as a devDependency, pruning anyway 原因:对electron没有严格要求的话可以忽略,不影响打包,但会影响第三 ...

  3. nginx 禁止某IP访问

    首先建立下面的配置文件放在nginx的conf目录下面,命名为blocksip.conf: deny 95.105.25.181; 保存一下. 在nginx的配置文件nginx.conf中加入:inc ...

  4. TP5用join进行查询出来后的循环id都是一样的

    这是因为join将两个表的所有字段都查询,id冲突了,所以需要设置名,或指定选择一个表的id 用field('a.*')

  5. Linux系列(29) - rpm包命名规则(1)

    RPM包命名规则 例如包名:httpd-2.2.15-15.el6.centsos.1.i686.rpm 软件包名-httpd 软件版本-2.2.15 发布的次数-15 el6.centos适合的Li ...

  6. Java面向对象系列(12)- Static关键字讲解

    场景一:静态变量 package oop.demo07; public class Student { private static int age;//静态的变量 一般多线程用的比较多 privat ...

  7. windows10 升级并安装配置 jmeter5.3

    一.安装配置JDK Jmeter5.3依赖JDK1.8+版本,JDK安装百度搜索JAVA下载JDK,地址:https://www.oracle.com/technetwork/java/javase/ ...

  8. PHP 7.4 checking for libzip 和 failed to open error_log 问题

    来源: https://hqidi.com/154.html 两个深坑,成年阿根廷龙踩出来的坑,网上都没找到解决方法,都是自己摸索出来的. 前面一切顺利: yum install -y libxml2 ...

  9. verifycode验证码模版

    # -*- coding:utf-8 -*- from django.shortcuts import HttpResponse def verifycode(request): # 引入绘图模块 f ...

  10. Redis 日志篇:无畏宕机快速恢复的杀手锏

    特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...