最近 NFLS 周賽,F 題需要字尾陣列,我不會,光榮掉到 20+ 名。
打完後就去補習了相關知識,覺得很巧妙,就來寫了一篇專欄
1. 字尾陣列的定義
字尾陣列(SA)儲存的是一個字串所有字尾的排序結果,其中第 SA[i] 表示所有字尾中第 $ i $ 小的字尾的開頭位置。
與之相對的是名次陣列 Rank,Rank[i] 表示以 $ i $ 開頭的字尾排第幾位。
舉個例子:
str: a a a b a a b a
SA: 8 1 5 2 6 3 7 4
Rank:2 4 6 8 3 5 7 1
2. 求法
有兩種方法倍增和 DC3,但我太菜了,只會倍增演算法。
2.1. 倍增
倍增,就是透過 $ i $ 步的答案推出 $ 2i $ 步的答案,從而在 $ O(\log n) $ 的時間內推出答案。那它跟字尾陣列有什麼關係呢?
假設我們已經求出了每個 $ i \sim i + 1 $ 的子串的 Rank:
str: a a a b a a b a
Rnk2:2 2 3 4 2 3 4 1
考慮將兩個字元和兩個字元拼在一起成為四個字元。
實際上,我們只需要將 Rank 拼在一起即可。為什麼呢?
考慮將這樣的二元組進行比較:
aaab Rank: (2, 3)
aaba Rank: (2, 4)
因為 Rank 反映了字典序情況,所以比較 Rank 相當於比較字典序
First: 2 = 2 相當於比較前兩個字元的字典序
Second:2 < 4 相當於比較後兩個字元的字典序
回到我們剛才的例子:
Rnk2:2 2 3 4 2 3 4 1
1st: 2 2 3 4 2 3 4 1
2nd: 3 4 2 3 4 1 0 0 (沒有時視為 0,是最小的序列)
Rnk4:2 3 5 7 3 4 6 1
於是我們就不斷把子串拼接拼接再拼接,拼接足夠多次直到長度 $ \ge n $ 即可。
使用基數排序,我們就可以 $ O(n \log n) $ 求出答案。
2.2. DC3
<++>(待更)
3. 實際應用
<++>(待更)