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. gpio模拟mdc/mdio通信

    本文主要是学习gpio模拟mdc/mdio通信. 运行环境是在ATMEL的sama5d35MCU,两个GPIO引脚模拟MDC/MDIO通信,读取百兆phy的寄存器的值. #include<lin ...

  2. Ncdu强大的磁盘查看命令

    简介 项目地址: https://dev.yorhel.nl/ncdu Ncdu (NCurses Disk Usage) 是一个基于 Ncurses 库的 du 命令的界面.它通过大家熟知的 du ...

  3. golang 判断前缀后缀、包含关系

    HasPrefix 判断字符串 s 是否以 prefix 开头:strings.HasPrefix(s, prefix string) bool HasSuffix 判断字符串 s 是否以 suffi ...

  4. Java8中list.sort的lamba表达式

    最近写代码,需要对list集合排序,IDEA总是黄色警告: Reports calls to Collections.sort(list, comparator) which could be rep ...

  5. PHP、JS一些用法

    PHP去除小数点后面的0,保留非零 floatval($num) PHP转数组var d = eval(数组d); PHP字符串转数组 $row['0'] = explode(";" ...

  6. 问卷星导入数据到SPSS,数据变成-3是什么原因?

    问卷星将数字“-3”表示为筛选或者跳转题:如果问卷中有设计筛选或者跳转,此时则会出现“-3”这个数字. 解决办法1 分析时首先进行筛选,然后再分析,便不会出现“-3”,而且一定需要这样进行.“筛选样本 ...

  7. JS手写call、bind、apply

    call方法的实现 Function.prototype.MyCall = function(content,...args){ const self = content || window; con ...

  8. 目标追踪(Object Tracking)概念的简要介绍

    现在我们有一个视频流,可以拆解出 N 个帧出来,这时候初始帧/某一帧中出现了一个我们感兴趣目标,我们希望在后续帧中对这个目标进行追踪,这时候就需要 CV 中的目标追踪: 目标追踪的效果如下: 虽然效果 ...

  9. ssm框架之springMVC拦截器

    1拦截器概述 1.1什么是拦截器? springMVC中的拦截器(Interceptor)类似于servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权 ...

  10. Appium + Python App自动化第一个脚本

    今天跟大家讲解一个Appium和Python App自动化的脚本.[1]打开你的夜神模拟器(或者连接你的手机) [2]打开桌面的Appium [3]下载你要测的App的apk文件,放到桌面[4]拖动你 ...