题意:求一个字符串的最长回文子串,限时15s ORZ,大概只有O(NlogN)的后缀数组的和O(N)的Manacher可以吧。这个算法刚巧看到就找来这题AC了。我觉得写的还蛮清楚的,代码如下。
#include<iostream>
#include<cstring>
#include<string>
#define M 10000005
using namespace std;
string s,tmp;
int casen,ans,rad[M];
int main()
{
while(cin>>tmp){
if("END"==tmp) break;
cout<<"Case "<<++casen<<": ";
int n=tmp.size();
s="";
memset(rad,0,sizeof(rad));
for(int i=0;i<n;i++){ //填充特殊字符
s+="#";s+=tmp[i];
}s+='#';
n=n*2+1;
int i=0,j=1,k; //BEGIN
while(i<n){
while(i-j>=0 && i+j<n && s[i-j]==s[i+j])
j++;
rad[i]=j-1; //rad[i]记录的是以i为中心左右做多可以扩展rad[i]个字符。
k=1;
while(k<=rad[i] && rad[i]-k!=rad[i-k]){
rad[i+k]=min(rad[i-k],rad[i]-k); //DP
k++;
}
i+=k; //
j=max(j-k,0); //
} //END
for(i=0;i<n;i++)
ans=max(ans,rad[i]);
cout<<ans<<endl;
ans=0;
}
return 0;
}
Manacher算法:最长回文子串,O(N)
这个是根据zlh神的博文http://www.starvae.com/?p=212#comment-1401 写的,看的资料下来这个是最容易理解这个DP的,神牛博客里的代码貌似是针对回文子串长度是偶数的情况写的,在实际情况中我们为了统一子串长度奇偶性,可以用在字符间添加分隔符的方法,使情况全部转化为长度是奇数的情况。例如"abc"添加分隔符后变成"#a#b#c#",然后略微修改的代码见上。有写的不对的地方请路过的大牛提醒
模版神马的,有预处理看起来长一些,其实很简单的10行。
int manacher(string tmp) //tmp是原始串
{
int n=tmp.size(),ans=0;;
string s;
memset(rad,0,sizeof(rad));
for(int i=0;i<n;i++){
s+="#";s+=tmp[i];
}s+='#';
n=n*2+1;
int i=0,j=1,k;
while(i<n){
while(i-j>=0 && i+j<n && s[i-j]==s[i+j])
j++;
rad[i]=j-1;
k=1;
while(k<=rad[i] && rad[i]-k!=rad[i-k]){
rad[i+k]=min(rad[i-k],rad[i]-k);
k++;
}
i+=k;
j=max(j-k,0);
}
for(i=0;i<n;i++)
ans=max(ans,rad[i]);
return ans; //ans是最长回文子串的长度
}