Manacher(马拉车算法)


序言

mannacher 是一种在 O(n)时间内求出最长回文串的算法

我们用暴力求解最长回文串长度的时间复杂度为O(n3)

很明显,这个时间复杂度我们接受不了,这时候,manacher也就是俗称的马拉车算法就出世了

算法描述

先考虑一种在O(n2)的时间复杂度内求解的算法

我们可以从左到右枚举字符串的每一个字符,以当前字符为起点,向左,和向右同事延伸来求解

回文长度,但我们深入分析一下,发现,这个算法明显是有漏洞的,它只能解决字符串长度为

为奇数的回文长度,偶数的字符串无法由它求出回文长度。

比如aba用该算法求出的值为3是正确的,但abba用该算法求出的值却是1,很明显,是错误的,那么我们考虑,

如何去优化该算法,使得奇数和偶数都能解决,我们考虑在字符串的首尾和字符

串间隔中插入一个特殊字符如\(,例如abba,插入后就变为了\)a\(b\)b\(a\)字符串的长

度由n变为了2n+1这样就可以保证字符串的长度为奇数了,证明很简单,2n定为偶数

则2n+1一定为奇数然后便可以通过上述算法求出目前的回文长度了。

但,n2 的算法仍然无法满足我们的需求,我们考虑继续优化,那么如何优化呢?

我们需要引入几个定义

下述定义用未插入特殊字符的字符串进行解释

1:回文中心,即一回文串的中心字符比如abcba这个回文串,从左向右数的第3个字符即c

便为其回文中心我们因为我们对字符串进行了处理,所以便保证了每一串都有其回文中心

2,回文半径,即回文串的最右边界到回文中心的字符个数(包含回文中心)

我们可以发现,每个串的回文半径的长度*2-1便是所求回文串的长度

所以,我们只要求出那个最大的回文半径便可得到最长回文串长度

那么,我们如何求解呢?

manacher算法的本质便是对上面所提的n2的优化

我们看下图,假设我们目前枚举到i,定义r为到目前为止的回文串的最右边界,即目前为止的所

有回文串中,最右的字符下标最大的那个下标;mid则为 r 所在回文串的回文中心

我们对i进行讨论

当i<r时因为i位于以mid为回文中心的回文串中,所以以i为回文中心的字符串有可能被以mid

为回文中心的字符串包含,假设被包含,我们利用回文串的对称性可知,以i关于mid的对称点也就是j点

为回文中心的字符半径等于以i为半径的回文半径

我们直接赋值即可

定义p数组为回文半径长度

那么我们如何判断呢?当r-i的长度要大于p [j] 时,p[j]一定没有超过mid的范围,那么,我们直接对称过去更新p[i]即可

反之,当r-i>r-i 表明p[j]有可能包含mid范围之外的数,我们无法将p[j]赋给p[i]便在范围内将r-i赋给p[i];

本质融合成一句代码便是

p[i]=p[mid*2-i]>mir-i?mir-i:p[mid*2-i];

我们求j的下标利用中点坐标公式求解即可

贴一发代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn =2e7+10;
char s[maxn];
char ns[maxn];
int p[maxn];
int getle(){
int len=strlen(s);
int j=2;
ns[0]='~';//设置枚举边界,字符串右侧带有换行,所以我们右侧不必放字符了
ns[1]='$';
for(int i=0;i<len;i++){
ns[j++]=s[i];
ns[j++]='$';
}
return j;
}
int manacher(){
int len=getle();
int mid=1;
int mir=1;
int ans=-1;
for(int i=1;i<len;i++){
if(mir>=i){
p[i]=p[mid*2-i]>mir-i?mir-i:p[mid*2-i];
}
else{
p[i]=1;
}
while(ns[i+p[i]]==ns[i-p[i]]){
p[i]++;
}
if(p[i]+i>mir){
mid=i;
mir=p[i]+i;
}
ans=max(p[i]-1,ans);
}
return ans;
}
int main(){
cin>>s;
cout<<manacher();
return 0;
}

完结撒花

manacher(马拉车算法)的更多相关文章

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

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

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

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

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

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

  4. manacher马拉车算法

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

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

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

  6. Manacher(马拉车)算法

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

  7. [模板] Manacher(马拉车)算法

    用途 求回文子串 做法 先考虑回文子串以某字符为中心的情况,即长度为奇数 推着做,记rad[i]为以i位置为中心的最大半径(包含中点) 考虑怎么求rad[i].找之前的一个右端点最靠右的位置p,设它的 ...

  8. Manacher(马拉车)算法详解

    给定一个字符串,求出其最长回文子串 eg:  abcba 第一步: 在字符串首尾,及各字符间各插入一个字符(前提这个字符未出现在串里). 如  原来ma  /*  a    b a    b   c ...

  9. Manacher's Algorithm 马拉车算法

    这个马拉车算法Manacher‘s Algorithm是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这 ...

随机推荐

  1. elaticsearch

  2. Sqlalchemy 事件监听与初始化

    sqlalchemy不仅仅能自动创建数据库,更提供了其他更强大的功能,今天要介绍的就是sqlalchemy中的事件监听,并将其应用到数据库的初始化中. 需求:当插入设置password字段时,自动加密 ...

  3. 逆流而上,7月阿里最新出炉的三面面经,年薪50W,我行您也行

    从7月份开始,打算找工作,一个偶然的机会,拉勾上一个蚂蚁金服的师兄找到我,说要内推,在此感谢姚师兄,然后就开始了蚂蚁金服的面试之旅.把简历发过去之后,就收到了邮件通知,10个工作日联系我,请耐心等待. ...

  4. Spring官方宣布:新的Spring OAuth2.0授权服务器已经来了

    1. 前言 记不记得之前发过一篇文章Spring 官方发起Spring Authorization Server 项目.该项目是由Spring Security主导的一个社区驱动的.独立的孵化项目.由 ...

  5. Leetcode 24. Swap Nodes in Pairs(详细图解一看就会)

    题目内容 Given a linked list, swap every two adjacent nodes and return its head. You may not modify the ...

  6. 洛谷 P3951 NOIP 2017 小凯的疑惑

    洛谷 P3951 NOIP 2017 小凯的疑惑 题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付 ...

  7. log4j升级到log4j2

    log4j升级到log4j2 1.导入依赖 log4j2应尽量使用同一版本,否则可能出现不兼容的情况 <!-- log4j2 start --> <!-- log4j-1.2-api ...

  8. Java面试题(JVM篇)

    JVM 194.说一下 jvm 的主要组成部分?及其作用? 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库 ...

  9. TCP/IP网络编程之字节序和网络字节序

    一.概要 本篇文章主要讲解基于.net中tcp/ip网络通信编程中的网络字节序.在自我进步的过程中记录这些内容,方便自己记忆的同时也希望可以帮助到大家.技术的进步源自于分享和不断的自我突破. 技术交流 ...

  10. android Studio(3.2.1) NDK配置

    1.创建as工程 2. 创建class类 3. 生成头文件 3.1 配置命令工具 添加工具: 配置工具: Program: $JDKPath$\bin\javah.exe Arugments:-d j ...