manacher马拉车算法

入门manacher最好文章:https://segmentfault.com/a/1190000003914228

我整理了模板代码:HDOJ3068马拉车模板

 1 //讲解  https://segmentfault.com/a/1190000003914228
 2 //manacher 算法模板
 3 //求最长回文串 O(N)
 4 #include <bits/stdc++.h>
 5 using namespace std;
 6 const int maxn=3e5+10;
 7 char s[maxn],c[maxn];
 8 int RL[maxn],maxright,pos,len;
 9 void init()     //初始化串
10 {
11     len=strlen(c);
12     for(int i=0;i<len;i++)
13     {
14         s[2*i]=‘@‘;
15         s[2*i+1]=c[i];
16     }
17     s[2*len]=‘@‘;
18     s[2*len+1]=‘\0‘;
19     len=2*len+1;
20     maxright=pos=0;
21     //memset(RL,0,sizeof(RL));
22 }
23
24 int manacher()
25 {
26     RL[0]=1;
27     int ans=1;
28     for(int i=1;i<len;i++)  //枚举对称轴
29     {
30         if(i<=maxright)     //第一种情况处理
31         {
32             int j=2*pos-i;
33             if(j<0)break;
34             RL[i]=min(RL[j],maxright-i);    //跳过重复的步骤
35         }
36         else RL[i]=1;
37         while(s[i-RL[i]]==s[i+RL[i]]&&i-RL[i]>=0&&i+RL[i]<len) RL[i]++;   //探查 新的回文串
38         if(i+RL[i]>=maxright) maxright=i+RL[i],pos=i;  //更新 最右端 和对称轴
39         ans=max(ans,RL[i]);
40     }
41     cout<<endl;
42     return ans-1;
43 }
44
45 int main()
46 {
47     while(scanf("%s",c)!=EOF)
48     {
49         init();
50         cout<<manacher()<<endl;      //小细节
51     }
52     return 0;
53 }

manacher算法能够O(N)求字符串的最长回文字串

回文串就是  :一个字符串  正读和反着读  是一样的。

举个例子:  12321   abccba   tattarrattat   aaaa  都是回文串

先介绍  

1:朴素求法

1:枚举区间左端点和右端点  for(i=0~n) for(j=i~n)  枚举O(N^2)

2:朴素判断该串是否为回文串            判断O(N)

总时间复杂度  O(N^3)  显然 很朴素,很慢

判断字符串是否为回文串

因为回文串具有中心对称性,所以回文串关于中心对称,可以从对称轴开始向左右移动匹配

2:稍加优化

枚举对称轴,从对称轴向两边延伸判断回文串。

由于回文串的长度为奇数和偶数时 对称轴的位置不同,对称轴的位置在字符的位置或是字符之间

对于长度为n的字符串,对称轴共有2*n-1个,每个对称轴平均向旁边延伸n/4个,总时间复杂度是O(N^2).

3:运用动态规划的思想O(N^2)

使用d[i][j]记录区间i到j的字符串是否为回文串

通过状态转移O(1)判断区间内字符串是否为回文串

枚举范围O(N^2);总时间复杂度O(N^2).

 1 bool d[maxn][maxn];
 2 char s[maxn];
 3
 4 void pd()
 5 {
 6     memset(d,0,sizeof(d));          //d[i][j] 表示 区间i~j上的是不是回文串
 7     int maxlen=0;
 8     int len=strlen(s);
 9     int l,r;
10     for(int line=1;line<len;line++)
11     {
12         for(int i=0;i+line-1<len;i++)
13         {
14             int j=i+line-1;
15             if(s[i]==s[j]&&(d[i+1][j-1]||j-i<=2))   //状态转移
16             {
17                 d[i][j]=1;
18                 l=i;
19                 r=j;
20                 maxlen=line;
21
22             }
23         }
24     }
25 }

4:manacher (马拉车算法)O(N)

马拉车算法主要解决了两个点

1)这样一种情况:

长回文串中包含的子回文串

ababa   计算了两次aba aba

如果长回文串很长,这种重复计算不可忽视

2)枚举对称轴时,回文串长度奇偶性的影响

通过在串中添加相同字符解决

这样把每个有效字符的下标都设为了奇数,穿插的’#’不会影响回文串

char:    # a # b # a #

i :     0 1 2 3 4 5 6

为了解决重复枚举回文字串的问题,引入一个数组(manacher的核心在这)

RL[i]表示以i为对称轴,向右到i+RL[i]-1向左到i-RL[i]+1 范围的串是回文串。

同时引入maxright记录此时处理过的回文串中最右面的位置

Pos记录该回文串的对称轴。

可以看出要处理的对称轴i一定在pos后面

分两种情况:

1)i<=maxright

2)i>maxright

If(i>maxright)  此时要从i开始向左右两侧朴素的查找最长回文串,同时更新maxright和pos

If(i<=maxright)去重就看它。此时对称轴i在一个以pos为对称轴,右边界maxright的回文串之内

i关于pos对称的位置j=2 * pos - i ,

以j为对称轴,范围在pos回文串之内的回文串一定和以i为对称轴的回文串部分相同

例如 b  abababa  c   pos指向中间的b maxright指向最后的a  i在最后的b   j在第二个b

If(RL[j]过大)       i+RL[j]>maxright  RL[i]=maxright-i;

if(RL[j]比较小      If(i+RL[i]<maxright  RL[i]=RL[j]

完成这一步之后i回文串继续向后匹配,同时更新maxright和pos

时间: 2024-10-26 22:16:07

manacher马拉车算法的相关文章

Manacher 马拉车算法

首先感谢 https://www.cnblogs.com/grandyang/p/4475985.html这篇文章,给了我很大帮助,解释的很详细. 最近在学习lyd的算法竞赛书,学到求最长回文串的时候就看到了O(n)复杂度的Manacher算法,书上给的是hash+二分做法,复杂度为O(nlgn),所以我就去学习了一下Manacher算法. 上面大佬的文章比较详细了,我在这里再说一下我当时比较迷惑地方,以及我注意的一些细节 我这个人就是和细节过不去,一点细节上解释不明白我就感觉自己还是不会 如何

Manacher&#39;s Algorithm ----马拉车算法

本文是我对博友BIT祝威 和Grandyang ,以及寒小阳关于最长回文子串上关于马拉车算法理解的整理,若是对我的整理有所不懂得,建议去看BIT祝威的博客,很详细,以下纯属个人不成熟的理解. 首先,得先了解什么是回文串(我之前就不是很了解,汗).回文串就是正反读起来就是一样的,如"abba".关于采用时间复杂度为O(n^2),以每个字符为中心去向两端遍历寻找最大回文串的方法,可以见我之前些的博客,戳这里! 当我们遇到字符串为"aaaaaaaaa",之前的算法就会发生

什么是马拉车算法(Manacher&#39;s Algorithm)?

提出问题 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.如a.aa.aba.abba等. 暴力解法 简单粗暴:找到字符串的所有子串,遍历每一个子串以验证它们是否为回文串.一个子串由子串的起点和终点确定,对于一个长度为n的字符串,共有n^2个子串.这些子串的平均长度大约是n/2,因此这个解法的时间复杂度是 \(O(n^3)\).明显不可取. 方法改进 回文子串是连续的,而且是对称的.长度为奇数回文串以最中间字符的位置为对称轴左右对

Manacher&#39;s Algorithm(马拉车算法)

Manacher Algorithm算法,俗称马拉车算法,其时间复杂为O(n).该算法是利用回文串的特性来避免重复计算的,至于如何利用,且由后面慢慢道来. 在时间复杂度为O(n^2)的算法中,我们在遍历的过程要考虑到回文串长度的奇偶性,比如说“abba”的长度为偶数,“abcba”的长度为奇数,这样在寻找最长回文子串的过程要分别考奇偶的情况,是否可以统一处理了? 一)第一步是改造字符串S,变为T,其改造的方法如下: 在字符串S的字符之间和S的首尾都插入一个“#”,如:S=“abba”变为T="#

2015 UESTC 搜索专题M题 Palindromic String 马拉车算法

Palindromic String Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/61 Description 秋实大哥喜欢探索新鲜事物,最近他发明了一种新型回文串,叫K重回文串!今天他想用它来考考小朋友们. 秋实大哥给出了与K重回文串有关的信息 任何字符串都属于0重回文串,包括空字符串.    一个长度为N的字符串S,S是K(k≥1)重回文串,当且仅当S是回文串,且其长

天梯杯 L2-008. 最长对称子串(马拉车算法应用)

最长对称子串 对给定的字符串,本题要求你输出最长对称子串的长度.例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11. 输入格式: 输入在一行中给出长度不超过1000的非空字符串. 输出格式: 在一行中输出最长对称子串的长度. 马拉车算法: 一)第一步是改造字符串S,变为T,其改造的方法如下: 在字符串S的字符之间和S的首尾都插入一个"#",如:S="abba"变为T="#a#b#b

吉哥系列故事——完美队形II(马拉车算法)

吉哥又想出了一个新的完美队形游戏! 假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则就是新的完美队形: 1.挑出的人保持原队形的相对顺序不变,且必须都是在原队形中连续的: 2.左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然如果m是奇数,中间那个人可以任意: 3.从左到中间那个人,身高需保证不下降,如果用H表示新队

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左

LeetCode(4) || Longest Palindromic Substring 与 Manacher 线性算法

LeetCode(4) || Longest Palindromic Substring 与 Manacher 线性算法 题记 本文是LeetCode题库的第五题,没想到做这些题的速度会这么慢,工作之余全部耗在这上面了,只怪自己基础差.本文主要介绍使用Manacher线性算法来求解字符串的最长回文子字符串. 题目 Given a string S, find the longest palindromic substring in S. You may assume that the maxim