淺談後綴數組SA

這篇博客不打算講多麼詳細,網上關於後綴數組的blog比我講的好多了,這一篇博客我是爲本身加深印象寫的。html

給大家分享了那麼多,容我自私一回吧~算法

參考資料:這位dalao的blog數組

1、關於求SuffixArray的一些變量定義:spa

1. sa[i]=j,表示第i名的後綴從j開始code

**存的是下標**xml

2. rnk[i]=j,從i開始的後綴是第j名的htm

**與sa爲互逆運算,存的是值**blog

3. tp[i]=j, 第二關鍵字爲i的後綴從j開始排序

**可理解爲第二關鍵字的SA,存的是下標**字符串

插入解釋一下第一關鍵字和第二關鍵字:

咱們要對全部的後綴進行排序,怎麼排呢?

開始時,咱們每一個字符的後綴存的只有它本身,因此它後綴的大小就是它的ASCII碼。

咱們把每一個字符i當作(s[i],i)的二元組,若是咱們直接丟pair<int,int>裏面而後std::sort,

這樣的時間複雜度是O(log^2 n)的,顯然不夠優秀。

因此就須要用到基數排序RadixSort,不瞭解的自行百度。

再使用倍增法,就可使咱們排序的時間複雜度下降到O(logn)。

因此咱們要對每一個後綴的前兩個字母進行排序,第一個字母的相對關係已經獲得了。

第i個後綴的第二個字母,就是第i+1個後綴的第一個字母,利用這個關係咱們第二個字母的相對關係也就知道了。

咱們的tp數組就是用來記錄它的,rnk[i]表示上一輪中第i個後綴的排名。

這裏引用神仙attack的一句話,我以爲講的很是到位:

對於一個長度爲w的後綴,你能夠形象的理解爲:

第一關鍵字針對前w2個字符造成的字符串,第二關鍵字針對後w2個字符造成的字符串

而後對每一個後綴的前4個字母組成的字符串排序,前8個,前16個...這就是倍增法求SA的流程了。

給出RadixSort的代碼:

void RadixSort(int a[],int b[]){//基數排序 
    for(int i=0;i<=m;i++)tax[i]=0;
    for(int i=1;i<=n;i++)tax[a[i]]++;
    for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
    for(int i=n;i>=1;i--)sa[tax[a[b[i]]]--]=b[i];
}

實在不能理解RadixSort也沒有關係,代碼很短

再給出求SA的代碼:

bool cmp(int *r,int a,int b,int k){
    return r[a]==r[b]&&r[a+k]==r[b+k];
}
void getSA(int a[],int b[]){
    for(int i=1;i<=n;i++)
        m=max(m,a[i]=s[i]-'0'),b[i]=i;
    RadixSort(a,b);
    for(int p=0,j=1;p<n;j<<=1,m=p){
        p=0;
        for(int i=1;i<=j;i++)b[++p]=n-j+i;
        for(int i=1;i<=n;i++)if(sa[i]>j)b[++p]=sa[i]-j;
        RadixSort(a,b);
        int *t=a;a=b;b=t;
        a[sa[1]]=p=1;
        for(int i=2;i<=n;i++)
            a[sa[i]]=cmp(b,sa[i],sa[i-1],j)?p:++p;
    }
}

關於代碼的解釋,有時間再填坑。本蒟蒻要學的算法還不少...SA就粗略地理解一下好了

開始填坑,先補充一個東西叫height數組。

height[i]表示排名爲i的後綴和排名爲i-1的後綴的最長公共前綴LCP。

暴力求解時間複雜度是O(n^2),根據一個性質height[i+1]>=height[i]-1

能夠O(n)時間內求出height數組,具體代碼:

 

void getHeight(){
    for(int i=1,j=0;i<=n;i++){
        if(j)j--;
        while(s[i+j]==s[sa[rnk[i]-1]+j])j++;
        height[rnk[i]]=j;
    }
}

 關於這個height數組,它能夠幹什麼,給出一張列表:

兩個後綴的最大公共前綴

lcp(x,y)=min(heigh[xy])lcp(x,y)=min(heigh[x−y]), 用rmq維護,O(1)查詢

可重疊最長重複子串

height數組裏的最大值

不可重疊最長重複子串

首先二分答案x,對height數組進行分組,保證每一組的最小height>=x

依次枚舉每一組,記錄下最大和最小長度,若sa[max]sa[min]>=x那麼能夠更新答案

本質不一樣的子串的數量

枚舉每個後綴,第i個後綴對答案的貢獻爲lensa[i]+1height[i]

相關文章
相關標籤/搜索