http://acm.hdu.edu.cn/showproblem.php?pid=3068

脑子转个弯总算看懂马拉车算法了。记录一下思路和模板。

马拉车算法是在O(n)的时间内求出最大回文子串。

一、变量和定义

为了对奇偶回文串统一处理,每个字符之间都加上一个字符,加上一个不会出现在原字符串的,

如"abba"变成"#a#b#b#a#";"aba"变成"#a#b#a#";无论是奇偶原串都变成了奇数新串,接下来对新串处理。

在一次遍历字符的过程中,变量名及意义

i:表示当前遍历到哪一个下标的字符

p[idx]:表示下标为idx的字符的回文半径,包括自身

id:目前遍历过程中能延展到最右的回文的中心点

mx:目前遍历过程中能延展到最右的下标位置,姑且称之为探测的最远长度

j:以id为中心的关于i对称的字符,在id的左边,已经遍历过了,p[j]已经确定了的


二、为何要记录每个遍历字符的回文半径呢?利用已有的信息为后面的遍历铺垫,否则就和中心扩展一样是O(n2)复杂度

1."abcecbd"加上'#'后变成"#a#b#c#e#c#b#d#"

下标 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

内容 # a # b # c # e # c #  b  #  d  #

p[i] 1 2 1 2 1 2 1 6 1 2 1  2  1  2  1

最长回文子串"#b#c#e#c#b#"的中心字符为e,下标为7,减去p[7]之后等于1,表示最长回文子串"bcecb"在原串"abcecbd"中的下标为1(从0算起)

2."abbc"加上'#'后变成"#a#b#b#c#"

下标 0 1 2 3 4 5 6 7 8

内容 # a # b # b # c #

p[i] 1 2 1 2 3 2 1 2 1

最长回文子串"#b#b#"的中心字符为#,下标为4,减去p[4]=3之后等于1,表示最长回文子串"bb"在原串"abbc"中的下标为1(从0算起)

3."aba"加上'#'后变成"#a#b#a#"

下标 0 1 2 3 4 5 6

内容 # a # b # a #

p[i] 1 2 1 4 1 2 1

最长回文子串"#a#b#a#"的中心字符为b,下标为3,减去p[3]=4之后等于-1,与前面不一致。原串最长回文子串应该是下标从0开始,则需要向右移动1位

4.在最左边加一个字符'$'(不会在原串中出现),则变成"$#a#b#a#"

下标 0 1 2 3 4 5 6 7

内容 $ # a # b # a #

p[i] 1 1 2 1 4 1 2 1

则最长回文子串"#a#b#a#"的中心字符为b,下标为4,减去p[3]=4之后等于0,与"aba"在"aba"的起始位置一致。

再回顾前2个例子

5."#a#b#c#e#c#b#d#"在首位加上'$'

下标 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

内容 $ # a # b # c # e # c  #  b  #  d  #

p[i] 1 1 2 1 2 1 2 1 6 1 2  1  2  1  2  1

最长回文子串"#b#c#e#c#b#"的中心字符为e,下标为8,减去p[8]=6之后等于2,但是最长回文子串"bcecb"在原串"abcecbd"中的下标为1,除以2可以得到,对于上一个例子0没有影响,再通过另一个例子验证。

6."#a#b#a#"在首位加上'$'

下标 0 1 2 3 4 5 6 7 8 9

内容 $ # a # b # b # c #

p[i] 1 1 2 1 2 3 2 1 2 1

最长回文子串"#b#b#"的中心字符为#,下标为5,减去p[5]=3之后等于2,但是最长回文子串"bb"在原串"abbc"中的下标为1,除以2可以得到

7.经过多方尝试都能通过验证。

首位加上一个不相干的字符后,原串的最长回文子串起始位置=(新串的最长回文中心id-p[id])/2


三、算法过程

1.如果i在mx左边,则i在以id为中心的回文子串内部,则与j对称;以j为中心的回文,i必然也有,对于j的回文情况p[j],再分两种情况讨论

(1)i+p[j]使得i右边大于等于mx,即(i+p[j])>=mx,则p[i]取(mx-i)即可

(2)(i+p[j])<mx,则p[i]=p[j]

2.如果i再mx右边,则先设p[i]=1

3.暂定了p[i],仍需要中心扩展。(马拉车的精髓就在这里,一次性可能定了一个巨大的p[i],而不是每次都从1慢慢中心扩展,节省时间)

4.防止中心扩展时候某一边会越界,尾部也加个乱七八糟的字符堵住,例如'!'

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define inf 0x3f3f3f3f
const double pi=3.1415926;
using namespace std;
int p[*+]; int Manacher(string s)
{
int ans=;
int id=,mx=;
memset(p,,sizeof(p));
int len=s.size();
for(int i=;i<len;i++)
{
int j=*id-i;///对称点
if(mx>i) ///i在已探测的范围内
{
if(mx-i>=p[j])
p[i]=p[j];
else
p[i]=mx-i;
}
else
p[i]=; ///暂定了p[i],还是有可能更大,中心扩展
while( s[ i+p[i] ] == s[ i-p[i] ] )///前后加入不相干字符,不会越界
p[i]++;
if(i+p[i]>mx)///更新最右点和对应的id
{
id=i;
mx=id+p[id];
}
ans=max(ans,p[i]);
}
return ans-;
} int main()
{
ios::sync_with_stdio(false);//加速
string str,s;
while(cin>>str)
{
s="$#";
int len=str.size();
for(int i=;i<len;i++)
{
s += str[i];
s += "#";
}
s=s+"!";
cout<<Manacher(s)<<endl;
}
return ;
}

运用了马拉车算法,本题还有2个可能出现的坑

  • 坑1:如果同c++的string输入字符串,需要加速
  • 坑2:string的拼接:str =str+ "a"加的运算产生的是一个新的对象,再把结果返回,而str += "a" 涉及到的应该是对象的引用,操作之后直接返回引用,避免了产生新的对象。因此,两者的性能有一定的差距。+=的写法更快。

真的是被坑得神不知鬼不觉,T了十几发才找到错误

hdu3068-最长回文-马拉车(Manacher)算法的更多相关文章

  1. hdu3068 最长回文(manacher 算法)

    题意: 给定字符串.求字符串中的最长回文序列 解题思路: manacher 算法 时间复杂度:O(N) 代码: #include <cstdio> #include <cstring ...

  2. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...

  3. HDU3068:最长回文(Manacher模板)

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  4. lintcode最长回文子串(Manacher算法)

    题目来自lintcode, 链接:http://www.lintcode.com/zh-cn/problem/longest-palindromic-substring/ 最长回文子串 给出一个字符串 ...

  5. 最长回文字符串(manacher算法)

    偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述:      回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...

  6. Palindrome(最长回文串manacher算法)O(n)

     Palindrome Time Limit:15000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit ...

  7. 最长回文子串—Manacher 算法 及 python实现

    最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串.   给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...

  8. hihocoder #1032 : 最长回文子串 Manacher算法

    题目链接: https://hihocoder.com/problemset/problem/1032?sid=868170 最长回文子串 时间限制:1000ms内存限制:64MB 问题描述 小Hi和 ...

  9. 第5题 查找字符串中的最长回文字符串---Manacher算法

    转载:https://www.felix021.com/blog/read.php?2040 首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一 ...

随机推荐

  1. 【2019.8.6 慈溪模拟赛 T3】集合(set)(线段树上DP)

    线段树上\(DP\) 首先发现,每个数肯定是向自己的前驱或后继连边的. 则我们开一棵权值线段树,其中每一个节点记录一个\(f_{0/1,0/1}\),表示在这个区间左.右端点是否连过边的情况下,使这个 ...

  2. 第02组Beta版本演示

    组长博客 组名:十一个憨比 本组组员: 学号 姓名 分工 贡献比例 181700413 黄智 写Beta冲刺的四次博客,写评审表,写word,统筹规划 9% 131700309 林闽沪 代码实现,答辩 ...

  3. MySQL实战45讲学习笔记:第四十四讲

    一.引子 这是我们专栏的最后一篇答疑文章,今天我们来说说一些好问题. 在我看来,能够帮我们扩展一个逻辑的边界的问题,就是好问题.因为通过解决这样的问题,能够加深我们对这个逻辑的理解,或者帮我们关联到另 ...

  4. 明解C语言 中级篇 第一章答案

    练习1-1 #include <stdio.h> #include<stdlib.h> int main() { srand(time()); ; printf("您 ...

  5. windows10 启动安卓模拟器会蓝屏的解决方案

    最近突然想用win10装个安卓模拟器玩游戏,然后提示vt被占用. 查了一下,了解到在windows 10 系统上,我们会用vmware,virtual box ,hyper-v,安卓模拟器,360安全 ...

  6. RocketMQ多master迁移至多master多slave模式

    一.项目背景 由于当前生产环境RocketMQ机器使用年限较长,已经过保,并且其中一台曾经发生过异常宕机事件.并且早期网络规划较乱,生产.开发.测试等网络没有分开,公司决定对当前网络进行规划,区分各个 ...

  7. gitLab 分支保护设置

    一.需求背景 开发当前开发的分支遇到暂时无法解决的问题,现在有需要开发其他应用,所以希望运维这边将当前有问题分支冻结,让其他人无法进行修改,待后续有时间在排查代码问题 二.Gitlab配置步骤 1.搜 ...

  8. 【MySQL】对数据库和表的增删改查

    数据库的基本概念 数据库的英文单词: DataBase 简称 : DB 什么是数据库? 用于存储和管理数据的仓库. 数据库的特点: 持久化存储数据的.其实数据库就是一个文件系统 方便存储和管理数据 使 ...

  9. abstract,virtual,override个人

    1.abstract 可以修饰类和方法,修饰方法时只声明不实现: 2.继承实现abstract类必须通过override实现abstract声明的方法,而virtual方法可选择override(重写 ...

  10. 三维网格精简算法(Quadric Error Metrics)附源码(转载)

    转载:  https://www.cnblogs.com/shushen/p/5311828.html 在计算机图形应用中,为了尽可能真实呈现虚拟物体,往往需要高精度的三维模型.然而,模型的复杂性直接 ...