HDU 3068 最长回文(manachar算法)
最长回文
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 25811 Accepted Submission(s):
9525
回文就是正反读都是一样的字符串,如aba,
abba等
两组case之间由空行隔开(该空行不用处理)
字符串长度len
<= 110000
abab
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算法)的更多相关文章
- hdu 3068 最长回文(manachar求最长回文子串)
题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...
- hdu 3068 最长回文 manacher算法(视频)
感悟: 首先我要Orz一下qsc,我在网上很难找到关于acm的教学视频,但偶然发现了这个,感觉做的很好,链接:戳戳戳 感觉这种花费自己时间去教别人的人真的很伟大. manacher算法把所有的回文都变 ...
- hdu 3068 最长回文(manachar模板)
Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等 Input 输 ...
- HDU 3068 最长回文 manacher 算法,基本上是O(n)复杂度
下面有别人的比较详细的解题报告: http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html 下面贴我的代码,注释在代码中: #include ...
- HDU 3068 最长回文 Manacher算法
Manacher算法是个解决Palindrome问题的O(n)算法,能够说是个超级算法了,秒杀其它一切Palindrome解决方式,包含复杂的后缀数组. 网上非常多解释,最好的解析文章当然是Leetc ...
- HDU - 3068 最长回文(manacher)
HDU - 3068 最长回文 Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Subm ...
- hdu 3068 最长回文 (Manacher算法求最长回文串)
参考博客:Manacher算法--O(n)回文子串算法 - xuanflyer - 博客频道 - CSDN.NET 从队友那里听来的一个算法,O(N)求得每个中心延伸的回文长度.这个算法好像比较偏门, ...
- HDU - 3068 最长回文(manacher算法)
题意:给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 分析: manacher算法: 1.将字符串中每个字符的两边都插入一个特殊字符.(此操作的目的是,将字符串 ...
- HDU - 3068 最长回文manacher马拉车算法
# a # b # b # a # 当我们遇到回判断最长回文字符串问题的时候,若果用暴力的方法来做,就是在字符串中间添加 #,然后遍历每一个字符,找到最长的回文字符串.那么马拉车算法就是在这个基础上进 ...
随机推荐
- luogu P1162 填涂颜色
https://www.luogu.org/problem/show?pid=1162 //其实很简单的吧 //就是最外圈加一圈0 ,然后把外圈里面的0都遍历了 //剩下的0 就变成2 就行了 #in ...
- JS判断输入值为正整数
JS中的test是原来是JS中检测字符串中是否存在的一种模式,JS输入值是否为判断正整数代码: <script type=”text/javascript”> function test( ...
- LightOJ 1030 Discovering Gold (期望)
https://vjudge.net/problem/LightOJ-1030 题意: 在一个1×N的格子里,每个格子都有相应的金币数,走到相应格子的话,就会得到该格子的金币. 现在从1格子开始,每次 ...
- Codeforces Round #417 (Div. 2) B. Sagheer, the Hausmeister
http://codeforces.com/contest/812/problem/B 题意: 有n层楼,每层楼有m个房间,1表示灯开着,0表示灯关了.最两侧的是楼梯. 现在每从一个房间移动到另一个房 ...
- POJ 2253 Frogger(dijkstra变形)
http://poj.org/problem?id=2253 题意: 有两只青蛙A和B,现在青蛙A要跳到青蛙B的石头上,中间有许多石头可以让青蛙A弹跳.给出所有石头的坐标点,求出在所有通路中青蛙需要跳 ...
- mysql导入source数据库
首先要确保数据库存在,如果不存在则创建 方法1 source 很智能,很方便,很快捷. # mysql -uroot -p Enter password: Welcome to the MySQL m ...
- vue2.0中v-on绑定自定义事件
vue中父组件通过prop传递数据给子组件,而想要将子组件的数据传递给父组件,则可以通过自定义事件的绑定. 每个Vue实例都实现了[事件接口],即: 1.使用 $on(eventName) 监听事件 ...
- UVA-11761-马尔可夫/记忆化搜索
https://vjudge.net/problem/UVA-11762 给出一个整数n,每次随机挑选一个小于等于n的素数,如果是n的因子,n变为n/x ,否则不变,问n变为1的期望挑选次数. f[i ...
- hdu 3264 09 宁波 现场 E - Open-air shopping malls 计算几何 二分 圆相交面积 难度:1
Description The city of M is a famous shopping city and its open-air shopping malls are extremely at ...
- 自定义控件---loadingView
自定义加载框,效果如图: 这个loadingView可以在图片下添加文案(加载中...),还可以自定义动画效果,自定义布局文件,屏蔽用户操作,点击返回键后隐藏. 库类中包含了一个LoadingDial ...