最长回文

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. NOIP 2018退役祭

    Day 0 实在是没啥特别想干的...路上看了一下FE的小玉的第四周目的视频...然后到了之后整理了一下东西,然后被slr教着学了一下一个叫翻棋的东西,然后立刻就上瘾了...然后就听slr先生教我滑铁 ...

  2. Python学习札记(二十九) 模块2

    参考:使用模块 NOTE 1.内建sys模块: #!/usr/bin/env python3 import sys 'a test module' __author__ = 'wasdns' def ...

  3. BZOJ 1566 【NOI2009】 管道取珠

    题目链接:管道取珠 这道题思路还是很巧妙的. 一开始我看着那个平方不知所措……看了题解后发现,这种问题有一类巧妙的转化.我们可以看成两个人来玩这个游戏,那么答案就是第二个人的每个方案在第一个人的所有方 ...

  4. TC 配置插件

    转载:http://hi.baidu.com/accplaystation/item/07534686f39dc329100ef310 1.插件下载地址:http://www.topcoder.com ...

  5. MySQL事务处理实现方法步骤

    需求说明: 案例背景:银行的转账过程中,发生意外是在所难免.为了避免意外而造成不必要的损失,使用事务处理的方式进行处理: A账户现有余额1000元,向余额为200的B账户进行转账500元.可能由于某原 ...

  6. kue

    尝试着看英文的文档,你发现他其实并不难. https://www.npmjs.com/package/kue

  7. C#通过WMI读取MAC地址

    该方法依赖WMI的系统服务,该服务一般不会被关闭;但如果系统服务缺失或者出现问题,该方法无法取得MAC地址,需要重启Windows Management Instrumentation服务. publ ...

  8. hdu4289最小割

    最近博客断更了一段时间啊,快期末了,先把这个专题搞完再说 最小割=最大流 拆点方法很重要,刚开始我拆点不对就wa了,然后改进后tle,应该是数组开小了,一改果然是 #include<map> ...

  9. HDU 5816 状压DP&排列组合

    ---恢复内容开始--- Hearthstone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java ...

  10. java--Quartz 定时执行

    第一步:引包(Maven) <!-- 定时任务 --> <dependency> <groupId>org.quartz-scheduler</groupId ...