您的位置:首页 > 其它

POJ3974 求字符串的最长回文子串的长度

2012-11-21 15:31 218 查看
回文串:如果某个字符串从左往右看与从右往左看是一样的,则称该字符串为回文串。

最长回文子串:求解一个字符串,它是某个给定字符串的子串,并且是回文串。

本题要求对于给定的字符串,求出它的最长回文子串的长度。可以采用Manacher算法在O(n)时间内求解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1000005;
char str
;	//原字符串
char s[N << 1];		//用'#'作为间隔填充之后的字符串
int p[N << 1];		//p[i]表示以第i个字符为中心的回文子串的长度加1
int len;
int ans;	//最长回文子串的长度

void Manacher()
{
int i;
int mx;	//mx表示当前回文子串扩展的最右端
int id;	//id表示mx是由哪个回文子串扩展出来的
len = (strlen(str) + 1) << 1;
for (i = 0; i < len; ++i)	//构造填充字符串
{
s[i] = '#';
p[i] = 0;
}
for (i = 0; str[i] != 0; ++i) s[(i + 1) << 1] = str[i];
s[(i + 1) << 1] = 0;
mx = 0;
ans = 0;
for (i = 1; s[i] != 0; ++i)	//求解p数组
{
if (mx > i) p[i] = min(mx - i, p[(id << 1) - i]);
else p[i] = 1;
while (s[i - p[i]] == s[i + p[i]]) ++p[i];
if (i + p[i] > mx)
{
mx = i + p[i];
id = i;
}
if (p[i] - 1 > ans) ans = p[i] - 1;	//更新最长回文子串的长度
}
}

int main()
{
int Case = 0;
while (scanf("%s", str) != EOF)
{
if (strcmp(str, "END") == 0) break;
Manacher();
printf("Case %d: %d\n", ++Case, ans);
}
return 0;
}


本题也可以使用后缀数组求解,但是使用后缀数组大概需要用10s左右的时间,而使用Manacher算法需要的时间不到300ms。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐