Manacher算法讲解

总有人喜欢搞事情,出字符串的题,直接卡掉了我的40分

I.适用范围

manacher算法解决的是字符串最长回文子串长度的问题。

关键词:最长 回文 子串

II.算法

1.纯暴力怎么写?

枚举每个字串(n^2)

判断是否回文(n)

综上,时间为n^3。

能解决n < 300的数据

2.优化的暴力

枚举点(n)

从点开始向两边逐个扩展,统计回文串的长度(上界n,但随机情况下很小)

综上,时间为n^2。

在随机数据下,实际表现能达到大概(n^2 / logn)的速度。

能解决5000左右的数据。

我们定义回文串的半径为回文串的回文中心到回文串的一端中间有多少个字符(不包含中心,包含端点)

比如回文串floatiyyitaolf的半径就是7,而vanav的半径是2。

对于长度是奇数和偶数的串要分类讨论。

给个示意的代码:

for(int i = ;i <= n;i++) {
回文串的半径 k = ;
while(s[i-k] == s[i+k]) k++;
ans = max(k*+,ans);
}

3.更优秀的算法——manacher

manacher可以看作是对上面那个n^2算法的进一步优化。

在枚举点统计回文串的过程中,我们其实是计算出了一些有用的信息,这些信息可以被后面的点使用,而无需重复计算(跟kmp有点像?)。

具体来说,我们从左向右枚举点,每次记录一下以这个点为中心的最长回文子串的半径(以i为中心的最长半径记为p[i])。

我们要试着利用回文的性质,因为子串是回文的,所以对于任意一个点x,有s[x - k] = s[x + k]  (k<= p[x])。这条性质可以省去重复比较字符的过程。

manacher的算法流程:

记录现在最大的(p[i] + i)为maxright,maxright对应的i为pos。

枚举下一个位置i时,i与maxright和pos有下面三种情况:

蓝星星代表i点,褐色星星代表i点关于pos的对称点j。

情况1:

p[j]较小,被p[pos]完全包含,那么由于pos的两边是对称的,那么蓝色区间一定是回文的,我们只要在蓝色区间的基础上再找更大的回文区间就可以了。

情况2:

p[j]较大,但我们只能保证红色区间是回文的,所以情况二中的蓝色区间是回文的,求更大的蓝色回文区间仍需要逐个扩展。

情况3:

此时i已经超出了maxright,不在红色范围,内此时只能逐个扩展。

每次扩展完毕要更新pos和maxright。

manacher还处理了一个问题:字串长度是奇数偶数要分类讨论。

具体方法是在每个字符的前后都保证有一个不在题目给的串里出现的字符,强行转化成奇数个字符。

AAADJ —> #A#A#A#D#J#

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int MAXN = + ; int n,ans;
int maxright,pos;
int p[MAXN<<];
char t[MAXN<<],s[MAXN<<]; inline int _max(int x,int y) {
return x > y ? x : y;
} inline int _min(int x,int y) {
return x < y ? x : y;
} int main() {
scanf("%s",t+);
n = strlen(t+);
s[] = '@';
for(register int i = ;i <= n;i++) {
s[i+i-] = '#';
s[i+i] = t[i];
}
n = n+n+; s[n] = '#';
for(register int i = ;i <= n;i++) {
if(i < maxright) p[i] = _min(p[pos+pos-i],maxright-i);
while(s[i-p[i]] == s[i+p[i]]) p[i]++;
ans = _max(ans,p[i]);
if(i+p[i] > maxright) maxright = i+p[i], pos = i;//要及时更新maxright
}
printf("%d\n",ans-);
return ;
}

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 (马拉车) 算法

    最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 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. win10解决vc++6.0不兼容问题方法

    这个方法我是可以用了 所以就写在着勒... 1 这个是百度云链接 先下载这个东西 放在电脑上 http://pan.baidu.com/s/1c2MihLA(一个MSDEV.EXE) 2然后找到这个目 ...

  2. Postgresql空库发布或者部分空库,模式,表处理备份流程

    --备份数据库结构pg_dump -h localhost -p 8101 -d qhsoam -s -f /tmp/nodata.sql --仅备份某模式和该模式下的数据表结构pg_dump -h ...

  3. bzoj 3589: 动态树【树链剖分+容斥】

    因为一开始调试不知道unsigned怎么输出就没有加\n结果WA了一上午!!!!!然而最后放弃了unsigned选择了&2147483647 首先链剖,因为它所给的链一定是某个点到根的路径上的 ...

  4. ionic2 如何引入第三方cordova插件

    例如:cordova-plugin-wechat 这个插件可以做微信登录,分享支付等 首先第一步:ionic plugin add cordova-plugin-wechat --variable w ...

  5. 爬虫—Requests高级用法

    Requests高级用法 1.文件上传 我们知道requests可以模拟提交一些数据.假如有的网站需要上传文件,我们也可以用requests来实现. import requests files = { ...

  6. 8. VIM 系列 - 利用 VIM 8.1 版本编译项目和GDB调试

    目录 term 模式 termdebug 模式 VIM版本安装请参考: 0. VIM 系列 - 源码升级最新版本vim term 模式 输入:term 打开此模式,效果如下 这个模式有编辑文本窗口和s ...

  7. Golang 入门 : 理解并发与并行

    Golang 的语法和运行时直接内置了对并发的支持.Golang 里的并发指的是能让某个函数独立于其他函数运行的能力.当一个函数创建为 goroutine 时,Golang 会将其视为一个独立的工作单 ...

  8. ls -l 详解

    ls -l 是文件系统的一个命令,用来查询当前路径的文件的属性.大小等详细信息

  9. [POI2009]SLO

    Description 对于一个1-N的排列(ai),每次你可以交换两个数ax与ay(x<>y),代价为W(ax)+W(ay) 若干次交换的代价为每次交换的代价之和.请问将(ai)变为(b ...

  10. (六)SpringIoc之延时加载

    Spring容器初始化时将所有scope = singleton的bean进行实例化. 通常情况下这是一件好事,因为这样在配置中的错误会更容易发现.但是如果不想spring容器初始化就实例化就要用到延 ...