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. org.springframework.web.struts.DelegatingActionProxy

    之前也不知道用的是哪个版本的spring jar 包,后来换了之后发现问题出来了, 00:08:00,364 ERROR RequestProcessor:296 - No action instan ...

  2. ubuntu 12.04 alt+tab无法切换窗口的问题(转载)

    转自:http://www.2cto.com/os/201209/153282.html ubuntu 12.04 alt+tab无法切换窗口的问题   安装cpmpiz配置管理程序.   sudo ...

  3. strncasecmp与strcasecmp用法(转载)

    转自: http://blog.csdn.net/acb0y/article/details/5333334 strcasecmp strcasecmp(忽略大小写比较字符串)  相关函数 bcmp, ...

  4. E20170524-hm

    logging   n. <美>伐木搬运业; 记录,存入; 航行日志; inversion  n. 倒置; 转化; (尤指词序) 倒装; (染色体的) 倒位; reversion   n. ...

  5. Element-wise operations

    Element-wise operations An element-wise operation operates on corresponding elements between tensors ...

  6. 【原创】《从0开始学Elasticsearch》—集群健康和索引管理

    内容目录 1.搭建Kibana2.集群健康3.索引操作 1.搭建Kibana 正如<Kibana 用户手册>中所介绍,Kibana 是一款开源的数据分析和可视化平台,因此我们可以借助 Ki ...

  7. #define及其用法

    #define     在#define中,标准只定义了#和##两种操作.#用来把参数转换成字符串,##则用来连接前后两个参数,把它们变成一个字符     串. #include<stdio.h ...

  8. SpringMVC之HttpMessageConverter

    http://blog.csdn.net/zmx729618/article/details/53034420 HttpMessageConverter接口: T read(Class<? ex ...

  9. Hello!六月

    把这里当做记事本应该没人介意吧: 太忙了!六月! ACM: 背包九讲

  10. synchronized(1)用法简介:修饰方法,修饰语句块

    注意: 同一个对象或方法在不同线程中才出现同步问题,不同对象在不同线程互相不干扰. synchronized方法有2种用法:修饰方法,修饰语句块 1.synchronized方法 是某个对象实例内,s ...