后缀数组构造方法:
1.倍增
直接参考刘汝佳蓝书
时间复杂度不优秀,但代码实现简单,细节处理较多,建议参考思路后背过代码。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ld long double
#define ll long long
#define ull unsigned long long
#define N 1001000
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,c[N],x[N],y[N],sa[N];
char s[N];
inline void solve_sa(){
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=0;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(int i=1;i<n;i++) x[sa[i]]= y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
int main(){
scanf("%s",s);
n=strlen(s);
m=128;
solve_sa();
for(int i=0;i<=n-1;i++) printf("%d ",sa[i]+1);
return 0;
}
2.DC3
常数大,实现复杂;
参考2009年论文。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ld long double
#define ll long long
#define ull unsigned long long
#define N 70010000
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int c[N],x[N],y[N],sa[N],rk[N];
inline void sort(int *rk,int *a,int *b,int n,int m){
for(int i=0;i<=m;i++) c[i]=0;
for(int i=0;i<n;i++) c[rk[a[i]]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) b[--c[rk[a[i]]]]=a[i];
}
inline bool cmp3(int *r,int x,int y){
return r[x]==r[y]&&r[x+1]==r[y+1]&&r[x+2]==r[y+2];
}
inline bool cmpt(int *r,int x,int y){
if(r[x]!=r[y]) return r[x]<r[y];
if(x%3==1) return c[x+1]<c[y+1];
else return !cmpt(r,y+1,x+1);//???
}
inline void dc3(int *rk,int *sa,int n,int m){
bool h=(n%3==1);if(h) rk[n++]=0;
int *rn=rk+n+2,*san=sa+n,ln=0,p;
for(int i=0;i<n;i++) if(i%3) x[ln++]=i;
rk[n]=rk[n+1]=0;
sort(rk+2,x,y,ln,m);
sort(rk+1,y,x,ln,m);
sort(rk,x,y,ln,m);
int ta=0,td=(n+1)/3;
#define F(x) (x/3)+(x%3==1?0:td)
rn[F(y[0])]=p=1;
for(int i=1;i<ln;i++){
if(!cmp3(rk,y[i],y[i-1])) p++;
rn[F(y[i])]=p;
}
if(p<ln) dc3(rn,san,ln,p);
else for(int i=0;i<ln;i++)
if(rn[i]) san[rn[i]-1]=i;
for(int i=0;i<ln;i++)
if(san[i]<td) y[ta++]=san[i]*3;
sort(rk,y,x,ta,m);
#define G(x) (x>=td?(x-td)*3+2:x*3+1)
for(int i=0;i<ln;i++) c[y[i]=G(san[i])]=i;
c[n]=-1;
int i=0,j=h;p=0;
while(i<ta&&j<ln){
if(cmpt(rk,y[j],x[i])) sa[p++]=y[j++];
else sa[p++]=x[i++];
}
while(i<ta) sa[p++]=x[i++];
while(j<ln) sa[p++]=y[j++];
}
char s[N];
int n;
int main(){
scanf("%s",s);
for(n=0;s[n];n++) rk[n]=s[n]-'0'+1;
dc3(rk,sa,n,128);
for(int i=0;i<n;i++) printf("%d ",sa[i]+1);
return 0;
}
3.sais
常数小,不容易理解,但代码实现简单。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ld long double
#define ll long long
#define ull unsigned long long
#define N 2000000
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
template <typename T>
inline void gm(T*&bas,int size,T*& op){
op=bas;
bas+=size;
}
#define pus(x) (sa[cur[a[x]]--]=x)
#define pul(x) (sa[cur[a[x]]++]=x)
#define inds(lms)\
for(int i=1;i<=n;i++) sa[i]=-1;for(int i=1;i<=n;i++) sum[i]=0;\
for(int i=1;i<=n;i++) sum[a[i]]++;for(int i=1;i<=n;i++) sum[i]+=sum[i-1];\
for(int i=1;i<=n;i++) cur[i]=sum[i];for(int i=m;i>=1;i--) pus(lms[i]);\
for(int i=1;i<=n;i++) cur[i]=sum[i-1]+1;for(int i=1;i<=n;i++) if(sa[i]>1&&!tp[sa[i]-1]) pul(sa[i]-1);\
for(int i=1;i<=n;i++) cur[i]=sum[i];for(int i=n;i>=1;i--) if(sa[i]>1&&tp[sa[i]-1]) pus(sa[i]-1);
int sa[N],sum[N],cur[N],rk[N];
int A_bas[N<<4],*A_t;
inline void sais(int n,int *a){
int *tp;gm(A_t,n+1,tp);
int *p;gm(A_t,n+2,p);
tp[n]=1;
for(int i=n-1;i>=1;i--) tp[i]=(a[i]==a[i+1])?tp[i+1]:(a[i]<a[i+1]);
int m=0;for(int i=1;i<=n;i++) rk[i]=(tp[i]&&!tp[i-1])?(p[++m]=i,m):-1;
inds(p);int tot=0,*a1;gm(A_t,m+1,a1);p[m+1]=n;
for(int i=1,x,y;i<=n;i++){
if((x=rk[sa[i]])==-1) continue;
if(tot==0||p[x+1]-p[x]!=p[y+1]-p[y]) tot++;
else for(int p1=p[x],p2=p[y];p2<=p[y+1];p1++,p2++) if((a[p1]<<1|tp[p1])!=(a[p2]<<1|tp[p2])){
tot++;break;
}
a1[y=x]=tot;
}
if(tot==m) for(int i=1;i<=m;i++) sa[a1[i]]=i;
else sais(m,a1);
for(int i=1;i<=m;i++) a1[i]=p[sa[i]];
inds(a1);
}
char s[N];
int n,a[N],tr[200];
int main(){
A_t=A_bas;
scanf("%s",s+1);int n=strlen(s+1);
for(int i=1;i<=n;i++) tr[s[i]]=1;
for(int i=1;i<=200;i++) tr[i]+=tr[i-1];
for(int i=1;i<=n;i++) a[i]=tr[s[i]]+1;a[++n]=1;
sais(n,a);
for(int i=2;i<=n;i++) printf("%d ",sa[i]);
}