【參考部落格】
【定義】
【字尾】從第i位到字串結尾的子串
【解決問題】
從而解決
...................在字串中找子串
...................比較子串關係
...................查詢不同子串的數目
一般來說都是解決
字串和子串關係的問題
【演算法學習】
字尾陣列能夠在 nlogn的時間複雜度內求取出以下陣列
【注意】明白字串包含字元的範圍
sa 儲存,第 i 個數字表示的是字典序第 i 大的字尾是以 sa_i 開始的字尾
即 「排第幾的是哪個字尾」
rank 儲存,從第i位開始的字尾的字典序排名是 i
即 「某個字尾排第幾個」
對sa的求取,我們可以看作對所有的字尾進行排序
而這個排序顯然如果直接莽的話肯定t,所以我們需要另外一種方法
這裡使用基數排序+倍增的方法進行優化
將所有的字尾進行排序得到sa,這是我們的目的
基數排序,是對兩個關鍵字的元素進行排序從而達到線性複雜度的方法
顯然,在當兩個字尾第乙個字元相等的情況下,我們不可避免的去用第二個字元進行比較
這裡我們需要注意到乙個事情
第 i 個字尾的第二個字元是第 i + 1 的第乙個字元
那這和直接莽好像沒有什麼區別?
所以我們就用到了倍增,每次確定字尾的以前 2 ^ k 長度的字串排序的順序
然後通過這個,就能夠求出 2 ^ ( k + 1 ) 長度的字尾的字首
通過,第 i 位的和第 i + k 位的,於是就能求出來
因為第乙個字元有可能一樣,導致有兩個字尾排名相等
所以總排名數和字尾長度不同
所以長度為2時同理
而當所有總排名和字尾長度相同時,這個時候就找到了所有
下面是對使用到的各個陣列的意義的描述:
c 桶,記錄第 i 位的元素有多少個
x 字尾 i 的第一關鍵字,所以最開始是等於第 i 位字元
y 第二關鍵字排名第 i 的字串,第一關鍵字的位置
【**】
首先求出所需要的幾個陣列的初值
//倍增的同時進行排序初始化int n = strlen(s+1
);
int m = 128
;
//m只需要大於 ascii(『z')即可
//因為第一步並不知道桶的規模
for (int i = 1; i <= n; i++)
++c[x[i] =s[i]];
//計算每乙個字元的數量,同樣的放在一起
for (int i = 2; i <= m; i++)
c[i] += c[i - 1
];
//求字首和
for (int i = n; i >= 1; i--)
sa[c[x[i]]--] =i;
//從後往前,這樣就能求出最開始順序
for (int k = 1; k <= n; k <<= 1)//【模板題】k是之前提到的,每次列舉的字串長度
【luogu p3809】
求乙個字串的sa
#include#includeview code#include
#include
using
namespace
std;
const
int maxn = 1000010
;char
s[maxn];
intsa[maxn];
intx[maxn], c[maxn], y[maxn];
void get_sa(char *s)
return;}
intmain()
【擴充套件】
lcp/height陣列的求取
演算法學習 字尾陣列
乙個字串的題,有姿勢水平的oiers的腦中應該要浮現出許多演算法 但是我沒有姿勢,也沒有水平,除了kmp和trie樹,什麼也想不起來。直到我學了它 字尾陣列!多虧這玩意兒,我現在什麼都想不起來了。字尾陣列幹嘛用的?主要處理同乙個字串中的重複子串問題。如何實現?注意到每乙個子串,都是乙個字尾的某個字首...
SA 字尾陣列 學習筆記
今天沒事幹,學了sa 其實是模擬賽掛了 引用資料 2009年國家集訓隊 洛谷 273期 我們記 sa i 為排名為 i 的字尾的開始位置。rk i 為開始位置為 i 的字尾的排名。我們採用基數排序,因為這樣在排序第一關鍵字的時候,第二關鍵字順序相對正確。舉例子就是21和12排序,因為你的程式不知道什...
字尾陣列(SA)學習記錄
乙隻只會字尾自動機卻不會字尾陣列的弱雞做了一下hdu 1403,結果sam被卡記憶體了,然後學習了一下sa。以下兩道題都是求lcs,區別在於字串長度。hdu 1403 1 include 2 include 3 include 4 include 5 define rank rank 6using ...