后缀数组

后缀数组构造方法:

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

常数小,不容易理解,但代码实现简单。

参考1

参考2

#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]);
}
上一篇:极客快讯第 5 期:袁隆平对抖音账号不知情,抖音回应;百度宣布组建智能汽车公司;北京滴滴和花小猪将于一周内完成司机疫苗接种;


下一篇:docker 搭建mssql2017