字尾陣列倍增演算法學習筆記

2021-09-30 00:21:29 字數 2716 閱讀 7900

字尾陣列(suffix array),簡稱sa陣列裡面儲存的是字串s從小到大或從大到小的所有字尾。

用處後續補,還不太清楚作用。

首先牢牢記住sa[i],意思是排第 i 的字尾是誰,而rank[i]代表字尾 i 排第幾。

然後先放上盜來的,

其實這個演算法思路還是很簡單的,難的地方在於編碼。如果不了解基數排序的話,這個算法學起來非常的吃力,建議先看學習一下基數排序。

對於乙個字串來說我們通過基數排序很輕鬆能把每乙個字元進行排序,這個時候是把每乙個字尾的第乙個字母進行了排序,如果按照樸素思維的話,就繼續進行第二個,第三個,一直到最後。

可如果我們利用了字尾的性質就可以簡化問題,假設我們已經對所有的字尾前k個字元進行了乙個排序,在進行下一次排序就可以直接對前2k個字元進行排序。why?已知每乙個字尾的前k個已經排好序了,對於字尾i來說,當進行下一次排序時,其實 i+k 到 i+2k-1這段字串(長度正好為k)順序我們已經知道了,因此下一次排序不需要憨憨的去長度加一的慢慢比較,而是把長度擴大二倍,也就是2k,所以排序長度每一次都是乘2倍增的.

現在在回頭看上面的,雖然每次是把 i 和 i+k作為乙個二元組,但實際是把長度從 k 變為了2k, 因此i + k 代表的是 i+k 到 i + 2k-1的排名,而不再是它本身。比如中第三次排序,其實是排的長度為8的情況。

對字串進行乙個基數排序,得到單個字元的rank陣列

倍增迴圈 l 一直到 l 大於等於字串長度n

把rank陣列賦值給rank1,然後把rank[i+k] 複製給rank2[i]

對rank2進行基數排序,得到tpsa

對rank1進行基數排序,得到sa

重新調整rank陣列

#include

#include

#include

using

namespace std;

//ss儲存字串,sa儲存 i到i+2k-1 的情況,tpsa是 i+k到i+2k-1的情況,作為中間輔助陣列

int ss[

100000

], sa[

100000

], tpsa[

100000

], rank[

100000

], rank1[

100000

], rank2[

100000

], cntrank[

100000];

int cnt[

256]

;void

build

(int n)

memset

(cntrank,0,

sizeof

(cntrank));

for(

int i=

0; i

)//對rank2進行基數排序,也就是確定後半段的排名,好在前半段確定位置

cntrank[rank2[i]]++

;for

(int i=

1; i

) cntrank[i]

+= cntrank[i-1]

;for

(int i=n-

1; i>=

0; i--

) tpsa[

--cntrank[rank2[i]]]

= i;

memset

(cntrank,0,

sizeof

(cntrank));

for(

int i=

0; i

)//對前半段進行基數排序,把前半段應該佔的區域確定好,然後根據求出的tpsa對每一段區域進行賦值

cntrank[rank1[i]]++

;for

(int i=

1; i

) cntrank[i]

+= cntrank[i-1]

;for

(int i=n-

1; i>=

0; i--

) sa[

--cntrank[rank1[tpsa[i]]]

]= tpsa[i]

;

rank[sa[0]

]=0;

//排名第乙個的不需要考慮

for(

int i=

1; i

)//如果排名為i的字尾的i-1的字尾的rank1或者rank2陣列不相等,就需要把名次加一 }}

}int

main()

build

(len)

; cout <<

"sa : "

;for

(int i=

0; i

) cout << sa[i]

<<

" ";

cout << endl;

cout <<

"rank : "

;for

(int i=

0; i

) cout << rank[i]

<<

" ";

cout << endl;

return0;

}

演算法學習筆記 倍增

倍增是一種非常重要的思想,在 acm oi 中有著豐富的應用。倍增的本質可以表述為,對於一種操作 f x 通過計算 f x f 2 x f 4 x cdots,f x 來加速求解 f n x 假設 f x 的時間複雜度為 o 1 那麼直接計算 f n x 的時間複雜度為 o n 而通過倍增的方法,則...

演算法學習 字尾陣列

乙個字串的題,有姿勢水平的oiers的腦中應該要浮現出許多演算法 但是我沒有姿勢,也沒有水平,除了kmp和trie樹,什麼也想不起來。直到我學了它 字尾陣列!多虧這玩意兒,我現在什麼都想不起來了。字尾陣列幹嘛用的?主要處理同乙個字串中的重複子串問題。如何實現?注意到每乙個子串,都是乙個字尾的某個字首...

字尾陣列 倍增演算法模板

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