芝士 字尾陣列 SA

2022-07-10 19:51:11 字數 1691 閱讀 3760

傳送門

它的工作原理是將待排序的元素拆分為k個關鍵字(比較兩個元素時,先比較第一關鍵字,如果相同再比較第二關鍵字……),然後先對第k關鍵字進行穩定排序,再對第k-1關鍵字進行穩定排序,再對第k-2關鍵字進行穩定排序……最後對第一關鍵字進行穩定排序,這樣就完成了對整個待排序序列的穩定排序。

​ --oi wiki

考慮對兩個字串進行比較

定義其為\(s1,s2\)

如果\([0,i]\)已經能比較出大小,那麼就不需要考慮\([i+1,lens)\)的關係了

反之,如果\([0,i]\)不能比較出大小,那麼就需要考慮\([i+1,lens)\)的關係

定義位置\(i\)的字串為\([i,lens)\)的字元

比如\(abaaba\)

\[0:abaaba\\1:baaba\\2:aaba\\3:aba\\4:ba\\5:a\\

\]考慮對於所有位置\(i\)字串按第一位進行排序

那麼排完序就會有

\[abaaba\\aaba\\aba\\a\\baaba\\ba

\]現在單獨考慮第二位的大小,考慮到字尾之間的聯絡,現在真的需要知道每乙個字尾具體是什麼樣子麼?

位置\(0\)的字串的第二位不就是位置\(1\)的字串的第一位?

那麼對於每乙個位置都可以找到乙個第一位與之第二位相對應

那麼我們就可以知道只考慮第二位的字尾之間的大小關係

然後我們知道第二位的大小關係,又知道第一位的大小關係、

那麼運用基數排序的思想,就可以知道前兩位,即\([0,1]\)的大小關係

按照pace2的內容進行遞推,

如果我們知道只考慮前k位的大小關係,即\([0,k-1]\)的大小關係

現在我們想求出只考慮\([0,2k-1]\)的大小關係

考慮對於位置\(i\)的字串,其\([k,2k-1]\)的字元就是位置\(i+k\)的前\(k\)位

故可以知道只考慮\([k,2k-1]\)的大小關係

那麼按照基數排序,就可以有\([0,2k-1]\)的大小關係

每一次基數排序的時間複雜度為\(o(n)\)

一共要倍增\(log_n\)次

所以總的時間複雜度為\(o(nlog_n)\)

#include#include#includeusing namespace std;

char s[1000005];

int lens,sa[1000005],m;//排名為i的位置&關鍵字的種類

int rk[1000005],tp[1000005];//位置i的排名&第二關鍵字排名為i的位置

int t[1000005],temp[1000005];//桶&臨時陣列

void ssort()//基數排序

void getsa()

ssort();

for(int k=1;k<=lens;k<<=1)

}int main()

{ ios::sync_with_stdio(false);

cin>>(s+1);

lens=strlen(s+1);

m='z';

getsa();

for(int i=1;i<=lens;i++)

cout《咕咕咕

SA 字尾陣列

首先一定要確定sa 是個什麼東西 sa i 表示的是排名為 i 的字尾是哪乙個 至於字尾 i的排名是多少,那個是ra nk i 當然啦 最最最難懂的就是基數排序 要是不用基數排序,每次對於乙個二元組直接so rt一下 這樣的複雜度是o nlog 2 對於二元組的基數排序應該是這樣做的 首先把所有元素...

字尾陣列SA

給定乙個字串s,按字典序排序s的所有子串 鬼知道什麼思想,好像沒有什麼思想。哦,想起來了,是倍增。考慮最簡單的字尾間o n o n 比較和快排o nlog n o n logn 總複雜度o n2lo gn o n 2log n 考慮優化字串間的比較,用倍增的思想,假設k 2 k 2 長度的已經比完了...

字尾陣列SA

原理 其本質就是把字串的所有字尾進行排序。用普通排序需要o nlogn 但是字串比較和數字比較不同,所以實際需要o n nlogn 為了讓這個過程快一點,所以有了倍增演算法,o nlogn 和dc3演算法,o n 倍增演算法比較簡單,也比較好寫,具體可以參考這個大佬的部落格。dc3演算法複雜一點,但...