回文串(PAM&Manacher)

​传送门​

思路:1. m a n a c h e r manacher manacher算法,用一个数组 p [ i ] p[i] p[i]维护下标 i i i的最大回文半径。

根据 m a x _ l e n = m a x ( p [ i ] − 1 ) , s t a r t _ i n d e x = ( p o s − p [ i ] ) 2 max\_len=max(p[i]-1),start\_index=\dfrac{(pos-p[i])}{2} max_len=max(p[i]−1),start_index=2(pos−p[i])

可得最大回文子串长度和开始下标。具体看代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2500,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
string a;
int Manacher(){
int len=0,mx=0,id=0,p[N]={},pos=0;
string s="$#";
for(int i=0;i<a.size();i++)
s.push_back(a[i]),s+="#";
int n=s.size();
for(int i=1;i<n-1;i++){
p[i]=(mx>i)?min(p[2*id-i],mx-i):1;
while(i-p[i]>=0&&s[i+p[i]]==s[i-p[i]]) p[i]++;
if(p[i]+i>mx) mx=p[i]+i,id=i;
if(p[i]>len) len=p[i],pos=i;
}
// st_index= (pos-len)/2;
// a[st_index--------st_index+len-2].
return len-1;
}
int main(){
while(cin>>a){
printf("%d\n",Manacher());
}
return 0;
}

时间复杂度 : O ( n ) :O(n) :O(n)

空间复杂度 : O ( 2 n ) :O(2n) :O(2n)(因为将字符串填充字符 # \# #便变成奇回文串,这样就不用讨论)

2. P A M PAM PAM,构建两棵树,一棵偶根树,一棵奇根树,用数组 f a i l [ i ] , l e n [ i ] fail[i],len[i] fail[i],len[i]分别维护结点 i i i最大回文后缀的结点 f a i l [ i ] fail[i] fail[i],回文串 i i i的长度 l e n [ i ] len[i] len[i]。取 m a x max max即可。

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) = O(n)= O(n)=结点数,(定理:一个字符串本质不同的回文串个数不超过其长度)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1205,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
char a[N];
int len[N],fail[N],cnt,num[N],cur,tri[N][26];
int main(){
while(~scanf("%s",a+1)){
mst(len),mst(fail),mst(num),mst(tri);
len[1]=-1,fail[0]=cnt=1;
int n=strlen(a+1);
int ans=0;
for(int i=1;i<=n;i++){
while(a[i-len[cur]-1]!=a[i]) cur=fail[cur];
if(!tri[cur][a[i]-'a']){
len[++cnt]=len[cur]+2;
int j=fail[cur];
while(a[i-len[j]-1]!=a[i]) j=fail[j];
fail[cnt]=tri[j][a[i]-'a'];
tri[cur][a[i]-'a']=cnt;
}
cur=tri[cur][a[i]-'a'];
ans=max(ans,len[cnt]);
}
printf("%d\n",ans);
}

return 0;
}

这里献上学习的博客,便于复习。

m a n a c h e r manacher manacher学习博客:

​传送门​

P A M PAM PAM学习博客

​传送门​