傳送門
它的工作原理是將待排序的元素拆分為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演算法複雜一點,但...