最长回文

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 25811    Accepted Submission(s):
9525

Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba,
abba等
 
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len
<= 110000
 
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
 
Sample Input
aaaa

abab

 
Sample Output
4
3
 

求解最长回文串之Manachar算法

问题类型:

输入一个字符串,求出其中最大的回文子串。子串的含义是:在原串中连续出现的字符串片段。

回文的含义是:正着看和倒着看相同,如abba和yyxyy。

这类问题对于一些小数据可以暴力枚举回文的中心点求解(处理好奇数和偶数长度的回文即可) 但是时间复杂度较高

利用manachar算法可以在O(n)时间内得到正确的答案

算法基本要点:

     首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:

     在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。

     为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊 字符,这样就不用特殊处理越界问题,比如$#a#b#a#。

下面以字符串12212321为例,经过上一步,变成了 S[] = "$#1#2#2#1#2#3#2#1#";

然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),比如S和P的对应关系:

S     #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #
P     1   2  1  2  5   2  1  4   1  2  1  6   1  2   1  2  1
(p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)

如何得到p数组嘞?

下面计算P[i],该算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。

这个算法的关键点就在这里了:如果mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。

“庖丁解牛”:

当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。

当 P[j] > mx - i 的时候,以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能一个一个匹配了。

对于 mx <= i 的情况,无法对 P[i]做更多的假设,只能P[i] = 1,然后再去匹配了

下面给出原文,进一步解释算法为线性的原因

if(mx > i)
p[i] = (p[*id - i] < (mx - i) ? p[*id - i] : (mx - i));
else
p[i] = ;
 
 
 
 
 
本题解法
 #include <iostream>
#include <string>
#include <string>
#include <algorithm>
using namespace std;
char s[], s1[];
int p[];
int manachar()
{
int i, j = ;
s1[j++] = '@';
s1[j++] = '#';
for (i = ; s[i]; i++) // 预处理字符串
{
s1[j++] = s[i];
s1[j++] = '#';
}
s1[j] = '\0'; int id = ; //id表示最大回文子串中心的位置
int mx = ; //id + P[id],也就是最大回文子串的边界
int len = ;
for (i = ; i < j; i++)
{
//这个算法的关键点就在这里了:如果mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。
if (i < mx) p[i] = min(mx - i, p[ * id - i]);
else p[i] = ;
while (s1[i + p[i]] == s1[i - p[i]]) p[i]++; // 更新p[i]的值(回文的长度)
if (i + p[i] > mx)
{ // 更新回文的中心点
id = i;
mx = id + p[i];
}
len = max(len, p[i]); // 最长回文串的长度
}
return len;
}
int main()
{
while (~scanf("%s", s))
{
int len = manachar();
printf("%d\n", len-);
}
return ;
}

还有一种预处理的方法,可以直接在原串上处理,不用在重新申请一个数组

不过要注意的是定义数组的时候,数组的大小要是字符串长度的二倍。

 #include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std; char s[];
int p[];
int manachar()
{
int len = strlen(s);
for (int i = len; i >= ; i --)
{ // 直接在原串上预处理
s[i*+] = s[i];
s[i*+] = '#';
} s[] = '@'; int id = , mx = , ans = ;
for (int i = ; i < len*+; i ++)
{
p[i] = i<mx ? min(mx-i,p[id*-i]) : ;
while (s[i+p[i]] == s[i-p[i]]) p[i] ++;
if (i+p[i] > mx)
{
id = i;
mx = i + p[i];
}
ans = max(ans,p[i]);
}
return ans-;
}
int main ()
{
while (~scanf("%s",s))
{
int ans = manachar();
printf("%d\n",ans);
}
return ;
}

HDU 3068 最长回文(manachar算法)的更多相关文章

  1. hdu 3068 最长回文(manachar求最长回文子串)

    题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...

  2. hdu 3068 最长回文 manacher算法(视频)

    感悟: 首先我要Orz一下qsc,我在网上很难找到关于acm的教学视频,但偶然发现了这个,感觉做的很好,链接:戳戳戳 感觉这种花费自己时间去教别人的人真的很伟大. manacher算法把所有的回文都变 ...

  3. hdu 3068 最长回文(manachar模板)

    Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等   Input 输 ...

  4. HDU 3068 最长回文 manacher 算法,基本上是O(n)复杂度

    下面有别人的比较详细的解题报告: http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html 下面贴我的代码,注释在代码中: #include ...

  5. HDU 3068 最长回文 Manacher算法

    Manacher算法是个解决Palindrome问题的O(n)算法,能够说是个超级算法了,秒杀其它一切Palindrome解决方式,包含复杂的后缀数组. 网上非常多解释,最好的解析文章当然是Leetc ...

  6. HDU - 3068 最长回文(manacher)

    HDU - 3068 最长回文 Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Subm ...

  7. hdu 3068 最长回文 (Manacher算法求最长回文串)

    参考博客:Manacher算法--O(n)回文子串算法 - xuanflyer - 博客频道 - CSDN.NET 从队友那里听来的一个算法,O(N)求得每个中心延伸的回文长度.这个算法好像比较偏门, ...

  8. HDU - 3068 最长回文(manacher算法)

    题意:给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 分析: manacher算法: 1.将字符串中每个字符的两边都插入一个特殊字符.(此操作的目的是,将字符串 ...

  9. HDU - 3068 最长回文manacher马拉车算法

    # a # b # b # a # 当我们遇到回判断最长回文字符串问题的时候,若果用暴力的方法来做,就是在字符串中间添加 #,然后遍历每一个字符,找到最长的回文字符串.那么马拉车算法就是在这个基础上进 ...

随机推荐

  1. Linux中重定向--转载

    转:http://blog.csdn.net/songyang516/article/details/6758256 1重定向 1.1      重定向符号 >               输出 ...

  2. codeforces 11 B.Jumping Jack 想法题

    B. Jumping Jack Jack is working on his jumping skills recently. Currently he's located at point zero ...

  3. shell 交互式选择(select)

    新建文件 sudo vi test.sh 写入如下内容: #!/bin/bash echo "What is your favourite OS?" select var in & ...

  4. mong大牛的blog

    MongoDB权威指南(3)-查询1.find方法介绍在不传入参数的情况下,find方法缺省使用  http://www.educity.cn/wenda/389594.html 这个归纳的比较好:可 ...

  5. C#用大石头Xcode做数据底层注意事项

    1.记得添加XCode.dll 和NewLife.Core.dll 2.记得把程序的框架改为 .net Framework4

  6. 6-9 😢 5小时的debug: 从rails 命令运行超慢开始->删除rails->删除ruby->删除rvm->安装上rvm->安装上ruby

    上午,莫名其妙的rails app不能用了,rails -v一查发现不存在.ruby -v发现是2.0的版本.很着急上火,因为很少使用过rvm这个ruby版本控制器.所以照官网文档.从新安装ruby, ...

  7. HDU1166 敌兵布阵_线段树

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. 阿里云负载均衡配置https记录

    配置前端协议是443,后端是80 问题1记录: 例如访问https://www.xxx.com,在后端服务器上面获取是http还是https请求协议实际上是http: 因为我们先请求负载均衡,负载均衡 ...

  9. 【hive】分组求排名

    分组求排名 相信好多使用Mysql的用户一定对分组求排名的需求感到发怵. 但是在hive或者oracle来说就能简单实现. 采用窗口函数:rank() over() / row_number() ov ...

  10. 蓝桥杯练习系统历届试题 带分数 dfs

    问题描述 100 可以表示为带分数的形式:100 = 3 + 69258 / 714. 还可以表示为:100 = 82 + 3546 / 197. 注意特征:带分数中,数字1~9分别出现且只出现一次( ...