前言
這篇部落格真難寫,暫定待更
定義
字尾陣列[suffixarray]是乙個一維陣列,簡稱sa,它儲存1到n的某個排列\(sa[1] ,sa[2],\dots,sa[n]\),並且保證\(suffix(sa[i]),\(1 \leq i < n\) 。也就是將s的n個字尾按字典序從小到大進行排序之後把排好序的字尾的編號順次放入sa中。
我們先從字尾陣列的入門題洛咕p3809講起
名詞解釋
好了接下來講如何構造字尾陣列
構造字尾陣列
首先我們將字尾編號
上圖中編號為1的字串為初始串,那麼按如圖所示給它編號為1-n。
s[i]:字串的第i位
sa[i]:就是字尾陣列,排名為i的字尾的編號
fst[i]:從編號為i的字尾的排名,即記錄第一關鍵字排名(備註:在很多部落格裡這個陣列的名字叫rank)
sec[i]:基數排序的第二關鍵字,表示以第二關鍵字排序時排名為i的字尾的編號
buk:桶
程式原理:
首先我們得形象理解fst,sec這兩個十足。簡單來說若當前字尾長度為len,fst是針對前\(\frac\)個字元的,sec是針對後\(\frac\)個字元的。
構造初始狀態,按第乙個字元基數排序的到了乙個序列,此時第乙個字母的相對關係我們已經知道了,暴力做法按第二個字母繼續排序,但事實上我們需要這樣做嗎?
實際上有一點非常重要:編號為i的字尾的第二個字母,實際是編號為i+1的字尾的第乙個字母。還有這種操作?就是有這種操作。又發現編號為i的字尾的第3,4個字母恰好是編號為i+2的字尾的前兩個字母。天哪。
這個性質有什麼意義呢?
這就意味如果我們不斷繼續下去,我們珂以使用上一層的sec更新本層的fst,而不需額外計算
於是之後我們將會用到\(i+4,i+8,i+16,\dots\)的字尾計算i的第一關鍵字,我們珂以將其簡單理解為一種倍增
於是我們愉快的一直計算,知道所有字尾的排名不同,然後結束
由於最多倍增計算到n,所以複雜度最大為\(\theta(n log_2(n))\)
這樣講珂能(確實)很難理解,我們直接進入程式流程。
程式流程:
初始化:
根據字串構造桶,並順便初始化fst陣列為該字母的ascii碼
這裡我們要給桶求乙個字首,求玩字首有什麼好處呢?這珂以使桶中的數直接對應排名,方便計算
倍增迴圈部分:
待更。p3809**實現:
#include #include #include #include #include using namespace std;
namespace suffixarray
inline void getprefixbuk()
inline void printsa()
void getsuffixarray()
}#undef maxn
#undef maxc
#undef ri
};int main()
字尾陣列思想(未完待更) 演算法 字尾陣列
考完了noip,雖然d2腦子進水,然而還是目測水到了一等獎,避免了gg。也是時候開啟一些新的演算法了。思來想去,還是搞一下字尾陣列吧。先簡單說明字尾陣列,是啥。字串字尾知道吧。陣列知道吧。字尾陣列就是在將乙個字串的所有字尾按照常見的字典序排法,排一下。顯然我們可以用stdsort來進行非常暴力的排序...
演算法,字尾陣列
字尾陣列就是將字串所有字尾排序後的陣列,設字串為s,令字尾suffix i 表示s i.len s 用兩個陣列記錄所有字尾的排序結果 然後就是怎麼快速求所有字尾的順序了,其中的關鍵是如何減少兩個字尾比較的複雜度 方法是倍增法,定義乙個字串的k 字首為該字串的前k個字元組成的串,關於在k 字尾上的定義...
字尾陣列 da演算法
sa陣列,他儲存1.n 的某個排列,sa 2 sa n 並且保證 suffix sa i suffix sa i 1 1 i 也就是將 s 的 n 個字尾從小到大進行排序之後把排好序的字尾的開頭位置順次放入 sa 中。rank陣列,他儲存的是每個位置的字尾子串的排名,與sa陣列是可以互逆的。heig...