您的位置:首页 > 其它

HDU 3068 Manacher 算法 求最大回文

2017-06-07 14:16 232 查看
给出一个只由小写英文字符a,b,c…y,z组成的字符串S,求S中最长回文串的长度.

回文就是正反读都是一样的字符串,如aba, abba等

这篇博客写的不错,时间复杂度为o(n)

https://www.felix021.com/blog/read.php?2040

首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#

然后用一个数组 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正好是原字符串中回文串的总长度)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>

using namespace std;
const int maxn = 220000+10;

char s1[maxn];
char s2[maxn];
int p[maxn];
int first(char *s1,char *s2)
{
int len=1;
s2[0]='$';
int i=0;
while(s1[i]!='\0')
{
s2[len++]='#';
s2[len++]=s1[i++];
}
s2[len++]='#';
return len;
}
void Manacher(int *p,char *str,int len)
{
memset(p,0,sizeof(p));
int mx=0,id=0;
for(int i=0;i<len;i++)
{
p[i]=mx>i?min(p[2*id-i],mx-i):1;
while(str[i+p[i]]==str[i-p[i]]) p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}
}
int main()
{
while(scanf("%s",s1)!=EOF)
{
int len=first(s1,s2);
Manacher(p,s2,len);
int ans=1;
for(int i=0;i<len;i++)
{
ans=max(ans,p[i]);
}
printf("%d\n",ans-1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: