字尾陣列(Suffix Array)

2021-07-26 10:50:50 字數 3448 閱讀 8694

字尾陣列是處理字串的有力工具。

sa儲存乙個字串按字典序排列的字尾,如圖

rank陣列儲存字尾i的名次,就是把sa反過來,上圖中

rank[1]==2,rank[2]==8

height陣列儲存相鄰兩個sa字尾之間公共字首的長度,如圖

思路:用倍增的方法對每個字元開始的長度為2

k2^k

2k子字串進行排序,求出排名,即 rank 值。k從0開始,每次加,當2

k2^k

2k大於n以後,每個字元開始的長度為2

k2^k

2k的子字串便相當於所有的字尾。並且這些子字串都一定已經比較出大小,即rank值中沒有相同的值,那麼此時的rank值就是最後的結果。每一次排序都利用上次長度為2k−

12^2k−1

的字串的rank值,那麼長度為2

k2^k

2k的字串就可以用兩個長度為2k−

12^2k−1

的字串的名排作為關鍵字表示,然後進行基數排序,便得出了長度為2

k2^k

2k的字串的rank值。

可以求出任意兩個字尾的最長公共字首。

性質1字尾(j)和字尾(k)的最長公共字首為height[rank[j]+1],height[rank[j]+2],height[rank[j]+3],…,height[rank[k]]中的最小值。

解釋:

首先這些字尾都是按照字典序排列過的,也就是說當第k位為a時,下乙個字尾第k位變成了b,那麼第k位以後就永遠不會變回a了。那麼height區間最小值意思就是在這個區間內,最靠前的變化位。如上圖,最小值1是因為第4排第2位的a變成了b,使得我們要求的兩個字尾的第二位也肯定不一樣,所以他們的最長公共字首為1。

首先得理解乙個性質

性質2height[rank[i]]>=height[rank[i-1]]-1

解釋:如下圖,紅色代表字尾(i-1),深藍色代表字尾(i),黃色代表字尾(k),即排名在紅色前面的那乙個,深綠色為它們的最長公共字首,即height[rank[i-1]]。那麼必定有乙個字尾(k+1)淺藍色,和深藍色的最長公共字首為height[rank[i-1]],即淺綠色(比深綠色少一格)。又因為性質1,所以淺藍色與深藍色排名的中間的height值最小為淺綠色長度,所以height[rank[i]](深藍色與他前一名的最長公共字首)一定是≥淺綠色的,即height[rank[i]]≥height[rank[i-1]]-1

利用這個性質,height就可以用乙個標記記錄height[rank[i-1]],減少列舉次數。

集訓隊**的**太難理解了,這裡是我的**:

這份**較長,但便於初學者理解,後面第二篇為簡化版

#include

#include

#define maxn 2005

#define max_num 256

char s[maxn]

;namespace suffixarray

for(

int i=

1;i)//基數排序後半段關鍵字

for(

int i=n-

1;i>=

0;i--

) tsa[

--cntb[b[i]]]

=i;//在後半段的基礎上基數排序前半段關鍵字

for(

int i=n-

1;i>=

0;i--

) sa[

--cnta[a[tsa[i]]]

]=tsa[i]

;//處理重複rank值

rank[sa[0]

]=0;

for(

int i=

1;i) rank[sa[i]

]=rank[sa[i-1]

]+(a[sa[i]

]!=a[sa[i-1]

]||b[sa[i]

]!=b[sa[i-1]

]);}

}void

getheight

(char str,

int n,

int sa,

int rank,

int height)

}}int r[maxn]

,sa[maxn]

,h[maxn]

;int

main()

printf

("\n");

for(

int i=

2;i<=n;i++

)printf

("hight[%d~%d]=%d\n"

,i-1

,i,h[i]);

return0;

}

簡化版**,效率高,**複雜度更低,需利用乙個性質

#include

#include

#include

using

namespace std;

const

int maxn=

2005

;int n;

char str[maxn]

;int sa[maxn]

,rk[maxn]

,h[maxn]

;int cnt[maxn]

,tsa[maxn]

,trk[maxn]

;void

getsa()

}void

geth()

}int

main()

printf

("\n");

for(

int i=

1;i)printf

("hight[%d~%d]=%d\n"

,i,i+

1,h[i]);

return0;

}

至少是我錯過的。。。

Suffix Array 字尾陣列

顧名思義,suffixarray 以下有時簡稱sa 和字串的字尾有關。字尾 字串中某個位置一直到結尾的子串。sa中討論包括了原串和空串 所以共有len 1個字尾。字尾陣列 字串的所有字尾組成的按字典序從小到大排好的陣列。由於sa中記錄的都是字串的字尾,所以sa只需要記錄其表示的字尾的起始位置。由於比...

字尾陣列suffix array

倍增演算法,時間複雜度o nlogn sa從小到大儲存相對大小的下標 理解lsd,x陣列,sa陣列 char s maxn int sa maxn t maxn t2 maxn c maxn n void build sa int m void build sa int m int cmp suff...

字尾陣列 Suffix Array

sa是一種解決多模板匹配問題的演算法。大致就是將字尾處理出來然後按照字典序排個序。時間主要浪費在排序上。sa陣列sa i 表示rk為i的字尾的開始位置。rk陣列rk i 表示以i位置開始的字尾的rank為多少。基數排序 先排個位,然後十位依次往下,穩定演算法。const int n 1e6 5 開二...