题目:
#1032 : 最长回文子串
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。
这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”
小Ho奇怪的问道:“什么叫做最长回文子串呢?”
小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”
小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?
小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”
它给的提示是要用中心往两边扩展的方法,但是还是超时。
所以只能用时间复杂度最小的O(N);
#include<vector>
#include<iostream>
using namespace std;
#include<cstring>
const int N=1000001;
int n, p[N];
char s[N], str[N];
#define _min(x, y) ((x)<(y)?(x):(y))
void kp()
{
int i;
int mx = 0;
int id;
for(i=n; str[i]!=0; i++)
str[i] = 0; //没有这一句有问题。。就过不了ural1297,比如数据:ababa aba
for(i=1; i<n; i++)
{
if( mx > i )
p[i] = _min( p[2*id-i], p[id]+id-i );
else
p[i] = 1;
for(; str[i+p[i]] == str[i-p[i]]; p[i]++)
;
if( p[i] + i > mx )
{
mx = p[i] + i;
id = i;
}
}
}
void init()
{
int i, j, k;
str[0] = '$';
str[1] = '#';
for(i=0; i<n; i++)
{
str[i*2+2] = s[i];
str[i*2+3] = '#';
}
n = n*2+2;
s[n] = 0;
}
int main()
{
int i, ans;
int ncase;
cin>>ncase;
while(ncase--)
{
cin>>s;
n=strlen(s);
init();
kp();
ans=0;
for(i=0;i<n;i++)
if(p[i]>ans) ans=p[i];
cout<<ans-1<<endl;
}
return 0;
}
ps:顺带普及一下这四种方法:
http://blog.youkuaiyun.com/kangroger/article/details/37742639:他总结的比较详细,只是里面一些代码都少打了一个=,大家查阅的时候要注意。
还有:最长子回文串
另外还有一个:点击打开链接