字尾陣列倍增法

2021-07-11 06:33:28 字數 2442 閱讀 6819

[**:

字尾陣列

【字尾陣列是處理字串的有力工具。字尾陣列是字尾樹的乙個非常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也並不遜色,而且它比字尾樹所占用的記憶體空間小很多。可以說,在資訊學競賽中字尾陣列比字尾樹要更為實用。】

1.1、基本定義

子串:字串s的子串r[i..j],i≤j,表示r串中從i到j這一段,也就是順次排列r[i],r[i+1],…,r[j]形成的字串。

字尾:字尾是指從某個位置i開始到整個串末尾結束的乙個特殊子串。字串r的從第i個字元開始的字尾表示為suffix(i),也就是suffix(i)=r[i..len(r)]。

大小比較:關於字串的大小比較,是指通常所說的「字典順序」比較,也就是對於兩個字串u、v,令i從1開始順次比較u[i]和v[i],如果u[i]=v[i]則令i加1,否則若u[i]

<

v[i]則認為u

<

v,u[i]

>

v[i]則認為u

>

v(也就是v

<

u),比較結束。如果i

>

len(u)或者 i

>

len(v)仍比較不出結果,那麼若len(u)

<

len(v)則認為u

<

v,若 len(u)=len(v)則認為u=v,若len(u)

>

len(v)則 u

>

v。從字串的大小比較的定義來看,s的兩個開頭位置不同的字尾 u和v進行比較的結果不可能是相等,因為 u=v的必要條件len(u)=len(v)在這裡不可能滿足。

字尾陣列:字尾陣列sa是乙個一維陣列,它儲存1..n的某個排列sa[1],sa[2],……,sa[n],並且保證 suffix(sa[i])

<

suffix(sa[i+1]),1≤i

<

n。也就是將s的n個字尾從小到大進行排序之後把排好序的字尾的開頭位置順次放入sa中。

名次陣列:名次陣列rank[i]儲存的是suffix(i)在所有字尾中從小到大排列的「名次」。

簡單的說,字尾陣列是「排第幾的是誰?」,名次陣列是「你排第幾?」。容易看出,字尾陣列和名次陣列為互逆運算。如圖1所示。

設字串的長度為n。為了方便比較大小,可以在字串後面新增乙個字元,這個字元沒有在前面的字元中出現過,而且比前面的字元都要小。在求出名次數組後,可以僅用o(1)的時間比較任意兩個字尾的大小。在求出字尾陣列或名次陣列中的其中乙個以後,便可以用o(n)的時間求出另外乙個。任意兩個字尾如果直接比較大小,最多需要比較字元n次,也就是說最遲在比較第n個字元時一定能分出「勝負」。

1.2、倍增演算法

倍增演算法的主要思路是:用倍增的方法對每個字元開始的長度為2k的子字串進行排序,求出排名,即rank值。k從0開始,每次加1,當2k大於n以後,每個字元開始的長度為2k的子字串便相當於所有的字尾。並且這些子字串都一定已經比較出大小,即rank值中沒有相同的值,那麼此時的rank值就是最後的結果。每一次排序都利用上次長度為2k-1的字串的rank值,那麼長度為2k的字串就可以用兩個長度為2k-1的字串的排名作為關鍵字表示,然後進行基數排序,便得出了長度為2k的字串的rank值。以字串「aabaaaab」為例,整個過程如圖2所示。其中x、y是表示長度為2k的字串的兩個關鍵字。

具體實現:

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];

int cmp(int *r,int a,int b,int l)

void da(int *r,int *sa,int n,int m)

這裡可以看到規定r[n-1]=0的好處,如果r[a]=r[b],說明以r[a]或r[b]開頭的長度為l的字串肯定不包括字元r[n-1],所以呼叫變數r[a+l]和r[b+l]不會導致陣列下標越界,這樣就不需要做特殊判斷。執行完上面的**後,rank值儲存在x陣列中,而變數p的結果實際上就是不同的字串的個數。這裡可以加乙個小優化,如果p等於n,那麼函式可以結束。因為在當前長度的字串中,已經沒有相同的字串,接下來的排序不會改變rank值。例如圖1中的第四次排序,實際上是沒有必要的。對上面的兩段**,迴圈的初始賦值和終止條件可以這樣寫:

for(j=1,p=1;p在第一次排序以後,rank陣列中的最大值小於p,所以讓m=p。

整個倍增演算法基本寫好,**大約25行。

演算法分析:倍增演算法的時間複雜度比較容易分析。每次基數排序的時間複雜度為o(n),排序的次數決定於最長公共子串的長度,最壞情況下,排序次數為logn次,所以總的時間複雜度為o(nlogn)。

字尾陣列(倍增法)

字尾陣列 suffix array 將某個字串的所有字尾按字典序排序後得到的陣列。演算法 樸素實現 直接將所有字尾進行排序,將n個長度為o n 的字串進行排序,時間複雜度o n 2 logn 倍增演算法 通過充分利用各個字尾之間的聯絡,將構造字尾陣列的最壞時間複雜度成功降至o n logn 倍增法實...

字尾陣列 倍增法詳解

主要是基於基數排序,如果基數排序沒弄懂 就會很難理解 首先從k 0開始,從字尾陣列裡面選取步長為2 k的字尾陣列的前子串 然後進行基數排序 如果排序後所有的名次陣列的值都不相同,那麼排序結束 否則,k 也就是步長翻倍 繼續排序。陣列sa sorted array 構造完成前表示關鍵字陣列,下標表示名...

字尾陣列 倍增演算法模板

關於字尾陣列的資料,可以看noi2009國家集訓隊 羅穗騫 的 字尾陣列 處理字串的有力工具 suffix array 倍增演算法 o n lgn build sa n 1,注意n 1 getheight n n 8 num 注意num陣列最後一位值為0,其它位須大於0 rank rank 0 n ...