最长回文子串简介:
相关算法及时间复杂度:
1.暴力求解:
2.中心扩展:
3.Manacher's Algorithm:
我只解释第三个:
马拉车:(要理解回文的特性)
1.数据结构: 源字符串+一维数组+中心标记符+最右扩展位置标记符+预处理后的字符串
char str[MAXN],newstr[3*MAXN];
int center,righ,p[MAXN*3];
2.预处理字符串:
newstr[0]='*';
int newlen=0;//预处理字符串之后的长度
for(int i=0;i<len;++i)
{
newstr[++newlen]=str[i];
newstr[++newlen]='*';
}
3.预处理标记符:
int center=0,righ=0;
4.算法实现:
for(int i=0;i<newlen;++i)
{
p[i]=(righ>i)?min(p[2*center-i],righ-i):1;//核心
while(newstr[i-p[i]]==newstr[i+p[i]])//扩展代码
++p[i];
if((i+p[i])>righ)//更新中心点,最右标记
{
righ=i+p[i];
center=i;
}
}
算法解释:
1.核心:
现在分为两种情况:
一、i < righ:
二、i >= righ:
第二种由于没有被以前的 center 包含,所以只能老实扩展 --> while(...) ++p[i];
主要是第一种情况:
一般来说, p[i] 就应该等于 i 关于 center 对称的 2*center-i 的 p,但是这里又要考虑两种情况:
如果p[i]=p[2*center - i]:
一.1: 那么 p[i] + i 可能会超出 righ,而我们又不能保证超出的部分也是合理的,所以,我们要保守估计,那么p[i] <= righ - i;(截掉了超出的部分)
一.2:但是,也有可能不会超出,即 p[i] + i <= righ ,这个时候,就放心大胆地把p [i] = p[2*center - i];
因此:p[i] = min(p[2*center - i],righ-i);
CODE:(以51NOD1088为例)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
const int MAXN = 1e3+10;
using namespace std;
char str[MAXN];
int p[MAXN],ans;
int main()
{
cin>>str;
char newstr[MAXN*3];
ans=1;
int len=strlen(str);
int center=0,righ=0;
newstr[0]='#';
int newlen=0;
for(int i=0;i<len;++i)
{
newstr[++newlen]=str[i];
newstr[++newlen]='#';
}
for(int i=0;i<newlen;++i)
p[i]=1;
for(int i=0;i<newlen;++i)
{
p[i]=(righ>i)?min(p[2*center-i],righ-i):1;
while(newstr[i-p[i]]==newstr[i+p[i]])
++p[i];
if((i+p[i])>righ)
{
righ=i+p[i];
center=i;
}
ans=max(ans,p[i]-1);
}
cout<<ans<<endl;
}
/*
daabaac
*/