1. 程式人生 > >[模板] 字尾陣列

[模板] 字尾陣列

概述

字尾陣列(Suffix Array), 是一種將字串所有後綴排序的一種演算法。
通過排序後的字尾,我們可以得到字串的許多性質,如重複出現的字串等。

演算法

常見的字尾陣列演算法有:

  1. 倍增演算法
    • 時間複雜度 $ O(n log n)
    • 常數較小
    • 程式碼較短
  2. DC3演算法
    • 時間複雜度 $ O(n)
    • 常數較大
    • 程式碼較長
  3. SA-IS演算法
    • 時間複雜度 $ O(n)
    • 常數較大
    • 程式碼很長
    • 窩三個月之前還會,現在就不會了

倍增演算法

放兩個連結:

程式碼

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//---------------------------------------
const int ssz=1e6+5;
char s[ssz];
int n,m,t1[ssz],t2[ssz],sa[ssz],c[ssz],*rank=t1,*tp=t2;
void pr(){
    rep(i,1,n)printf("%d %d %d\n",sa[i],rank[i],tp[i]);
}
void rsort(){
    rep(i,0,m)c[i]=0;
    rep(i,1,n)++c[rank[i]];
    rep(i,1,m)c[i]+=c[i-1];
    repdo(i,n,1)sa[c[rank[tp[i]]]--]=tp[i];
}
void suffixsort(){
    rep(i,1,n)rank[i]=s[i]-'0'+1,tp[i]=i;
    rsort();
//  pr();
    for(int w=1,p=0;p<n;m=p,w<<=1){
        p=0;
        rep(i,1,w)tp[++p]=n-w+i;
        rep(i,1,n)if(sa[i]>w)tp[++p]=sa[i]-w;
        rsort();
        swap(tp,rank);
        p=1,rank[sa[1]]=1;
        rep(i,2,n){
            rank[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
        }
//      pr();
    }
}
void init(){
    m=75;
    suffixsort();
    
}


int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>(s+1);
    n=strlen(s+1);
    init();
    rep(i,1,n)cout<<sa[i]<<' ';
    cout<<'\n';
    return 0;
}