後綴數組 學習筆記

後綴數組??!!

後綴數組是處理字符串的強有力的工具…..
在字符串處理當中,後綴樹和後綴數組都是非常有力的工具。其實後綴數組是後綴樹的一個非常精巧的替代品,它比後綴樹容易編程實現,能夠實現後綴樹的很多功能而時間複雜度也不太遜色,並且,它比後綴樹所佔用的空間小很多。可以說,在信息學競賽中後綴數組比後綴樹要更爲實用。 百度百科

後綴數組中變量的定義:

我們定義suffix(i) 爲以i開始到結束的後綴.
SA[i] :排第i 名的後綴的位置,排名是按照字典序來排的
Rank[i] : suffix(i) 排第幾
這時候我們就會發現SA[]Rank[] 互爲逆運算,即SA=Rank1
c[] :基數排序的數組
x[],y[] :第一二關鍵字的排名
我們怎樣構建後綴數組呢?
我們就是對所有的suffix(i) 進行排序,然後計算出SA[]Rank[]
要排序的話快排是O(nlogn) ,我們可以用基數排序來O(n) 的時間來進行排序

後綴數組的構建

一般兩種方法D3 和倍增
倍增相對來說比較好寫,所以我們這裏介紹倍增算法
我們就是先選定當前i 的排名作爲第一關鍵字,然後往後第2k 個字符的排名作爲第二個關鍵字,直到2k>n
後綴數組的奧祕就隱藏在下面這一張圖中
假如我們現在要構建aabab 的後綴數組
下面是倍增求排名的過程
這裏寫圖片描述
下面是SARank 數組
這裏寫圖片描述

代碼

後綴數組的構建難理解的就是基數排序;

void Build_SA()
{
    int n=Len,m=150;
    for (int i=0;i<m;i++)   c[i]=0;
    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[i]]++;
        for (int i=1;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]]&&((SA[i-1]+k>=n?-1:y[SA[i-1]+k])==(SA[i]+k>=n?-1:y[SA[i]+k]))?p-1:p++;//下一次排序繼續用,更新SA[]
        if (p>n) break;
        m=p;
    }   
}

Height數組

後綴數組比較有名還源於Height 數組
Height 數組的求解可以做到O(n)
這要基於Height[] 的一個性質
Height[i]>=Height[i1]1
這裏的i 指的是排名

void Built_Height()
 {
    for (int i=0;i<n;++i) Rank[SA[i]]=i;//利用逆運算的性質求出Rank
    int k=0;Height[0]=0;
    for (int i=0;i<n;++i)
    {
        if (!Rank[i]) continue;
        if (k) --k;
        int j=SA[Rank[i]-1];
        while (i+k<n&&j+k<n&&s[i+k]==s[j+k]) 
            ++k;//根據性質來求
        Height[Rank[i]]=k;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章