關於字尾陣列的倍增演算法和height陣列

2022-05-20 08:02:44 字數 3103 閱讀 8215

自己看著大牛的**學了一下字尾陣列,看了好久好久,想了好久好久才懂了一點點皮毛tat

然後就去刷傳說中的字尾陣列神題,poj3693是進化版的,需要那個相同情況下字典序最小,搞這個搞了超久的說。

先簡單說一下字尾陣列。首先有幾個重要的陣列:

·sa陣列(字尾陣列):儲存所有字尾排序後從小到大的序列。[即sa[i]=j表示排名第i的字尾編號為j]

·rank陣列(名次陣列):記錄字尾的名次。[即rank[i]=j表示編號為i的字尾排名第j]

用倍增演算法可以在o(nlogn)時間內得出這兩個陣列。

具體過程如下:

即每次長度增加一倍,直接用前面算出的排名作為關鍵字,問題轉化為給有兩個關鍵字的序列排序,這裡可以用基數排序,每次排序時間為n,一共進行了logn次,所以總共時間複雜度為o(nlogn)。要注意如果乙個字串包含另乙個字串,長度小的較小,那就是說如果沒有第二關鍵字,把第二關鍵字預設為0即可。具體如下:

陣列y儲存的是對第二關鍵字排序的結果

陣列wr儲存的是對第二關鍵字排序後的rank值

ln為當前子串的長度

rank值為排名,在這裡即為關鍵字的值

排序時如果兩個關鍵字相同即預設位置前的較小,那麼我們先按照第二關鍵字排序,再按照第一關鍵字排序,最後排出來的就是第一第二關鍵字合併的結果(基數排序的方法)

下一步是計算新的rank值。這裡要注意的是,可能有多個字串的

rank值是相同的,所以必須比較兩個字串是否完全相同,wr陣列的值已經沒有必要儲存,為了節省空間,這裡用wr陣列儲存rank值。

一直做到所有字尾的排名不同結束,時間複雜度為o(nlogn)。

字尾陣列的大部分應用都跟乙個很重要的height陣列有關。

height陣列定義:定義height[i]=suffix(sa[i-1])和suffix(sa[i])的最長公共字首,也就是排名相鄰的兩個字尾的最長公共字首

。對於j和k,不妨設rank[j]suffix(j)

和suffix(k)

的最長公共字首為

:height[rank[j]+1], height[rank[j]+2], height[rank[j]+3],

…, height[rank[k]]

中的最小值。

h陣列有以下性質:h[i]≥h[i-1]-1

證明:設suffix(k)是排在suffix(i-1)前一名的字尾,則它們的最長公共字首是h[i-1]。那麼suffix(k+1)將排在suffix(i)的前面(這裡要求h[i-1]>1,如果h[i-1]≤1,原式顯然成立)並且suffix(k+1)和suffix(i)的最長公共字首是h[i-1]-1,所以suffix(i)和在它前一名的字尾的最長公共字首至少是h[i-1]-1。因此得證。(如圖)

按照h[1],h[2],……,h[n]的順序計算,並利用h陣列的性質,時間複雜度可以降為o(n)。

實現的時候其實沒有必要儲存h陣列,只須按照h[1],h[2],……,h[n]的順序計算即可。

標程如下:

1 #include2 #include3 #include4 #include5

#define maxn 11000

6using

namespace

std;78

intsa[maxn],rank[maxn],y[maxn],rsort[maxn];

9int

wr[maxn],n,a[maxn],height[maxn];

1011

//cmp 第一關鍵字且第二關鍵字相同

12bool cmp(int k1,int k2,int ln)

13int mymax(int x,int q)

1415

void get_sa(int m) //

構建sa字尾陣列

1652

//得到新的rank陣列

53 m=p; ln*=2;//

m個rank ln長度54}

55 a[0]=0; sa[0]=0;56

}5758void

get_he()

5970}71

72int

main()

7383

for (i=1;i<=n;i++)

84 m=mymax(m,a[i]);

85 get_sa(m+10

);86

for(i=1;i<=n;i++)

87 printf("

%d "

,sa[i]);

8889 }

字尾陣列

做poj3415的時候感覺上面那個**有點小瑕疵誒~

還有乙個地方:

可以注意一下~~

字尾陣列 倍增演算法模板

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

利用倍增演算法的字尾陣列

仍然不是很懂,貼篇文章放在這兒希望有朝一日能頓悟吧。老天,乙個字尾陣列不知道看了多少天,最後終於還是看懂了啊!最關鍵的就是一會兒下標表示排名,一會用數值表示排名繞死人了。我不知道手跑了多少次才明白過來。其實我也建議初學者手跑幾遍,但是一定要注意陣列的意義,否則就是無用功。s 輸入的字串,預處理的時候...

字尾陣列倍增演算法模板詳解

2009國家集訓隊 字尾陣列 處理字串的有力工具 羅穗騫 bool cmp int r,int a,int b,int l void init int r,int sa,int n,int m for i 0 i n i rk sa i i int k 0 for i 0 i n 1 h rk i ...