自己看著大牛的**學了一下字尾陣列,看了好久好久,想了好久好久才懂了一點點皮毛tat
然後就去刷傳說中的字尾陣列神題,poj3693是進化版的,需要那個相同情況下字典序最小,搞這個搞了超久的說。
先簡單說一下字尾陣列。首先有幾個重要的陣列:
·sa陣列(字尾陣列):儲存所有字尾排序後從小到大的序列。[即sa[i]=j表示排名第i的字尾編號為j]
·rank陣列(名次陣列):記錄字尾的名次。[即rank[i]=j表示編號為i的字尾排名第j]
用倍增演算法可以在o(nlogn)時間內得出這兩個陣列。
具體過程如下:
即每次長度增加一倍,直接用前面算出的排名作為關鍵字,問題轉化為給有兩個關鍵字的序列排序,這裡可以用基數排序,每次排序時間為n,一共進行了logn次,所以總共時間複雜度為o(nlogn)。要注意如果乙個字串包含另乙個字串,長度小的較小,那就是說如果沒有第二關鍵字,把第二關鍵字預設為0即可。具體如下:
陣列y儲存的是對第二關鍵字排序的結果
陣列wr儲存的是對第二關鍵字排序後的rank值
ln為當前子串的長度
rank值為排名,在這裡即為關鍵字的值
排序時如果兩個關鍵字相同即預設位置前的較小,那麼我們先按照第二關鍵字排序,再按照第一關鍵字排序,最後排出來的就是第一第二關鍵字合併的結果(基數排序的方法)
下一步是計算新的rank值。這裡要注意的是,可能有多個字串的
rank值是相同的,所以必須比較兩個字串是否完全相同,wr陣列的值已經沒有必要儲存,為了節省空間,這裡用wr陣列儲存rank值。
一直做到所有字尾的排名不同結束,時間複雜度為o(nlogn)。
字尾陣列的大部分應用都跟乙個很重要的height陣列有關。
height陣列定義:定義height[i]=suffix(sa[i-1])和suffix(sa[i])的最長公共字首,也就是排名相鄰的兩個字尾的最長公共字首
。對於j和k,不妨設rank[j]suffix(j)
和suffix(k)
的最長公共字首為
:height[rank[j]+1], height[rank[j]+2], height[rank[j]+3],
…, height[rank[k]]
中的最小值。
h陣列有以下性質:h[i]≥h[i-1]-1
證明:設suffix(k)是排在suffix(i-1)前一名的字尾,則它們的最長公共字首是h[i-1]。那麼suffix(k+1)將排在suffix(i)的前面(這裡要求h[i-1]>1,如果h[i-1]≤1,原式顯然成立)並且suffix(k+1)和suffix(i)的最長公共字首是h[i-1]-1,所以suffix(i)和在它前一名的字尾的最長公共字首至少是h[i-1]-1。因此得證。(如圖)
按照h[1],h[2],……,h[n]的順序計算,並利用h陣列的性質,時間複雜度可以降為o(n)。
實現的時候其實沒有必要儲存h陣列,只須按照h[1],h[2],……,h[n]的順序計算即可。
標程如下:
1 #include2 #include3 #include4 #include5字尾陣列#define maxn 11000
6using
namespace
std;78
intsa[maxn],rank[maxn],y[maxn],rsort[maxn];
9int
wr[maxn],n,a[maxn],height[maxn];
1011
//cmp 第一關鍵字且第二關鍵字相同
12bool cmp(int k1,int k2,int ln)
13int mymax(int x,int q)
1415
void get_sa(int m) //
構建sa字尾陣列
1652
//得到新的rank陣列
53 m=p; ln*=2;//
m個rank ln長度54}
55 a[0]=0; sa[0]=0;56
}5758void
get_he()
5970}71
72int
main()
7383
for (i=1;i<=n;i++)
84 m=mymax(m,a[i]);
85 get_sa(m+10
);86
for(i=1;i<=n;i++)
87 printf("
%d "
,sa[i]);
8889 }
做poj3415的時候感覺上面那個**有點小瑕疵誒~
還有乙個地方:
可以注意一下~~
字尾陣列 倍增演算法模板
關於字尾陣列的資料,可以看noi2009國家集訓隊 羅穗騫 的 字尾陣列 處理字串的有力工具 suffix array 倍增演算法 o n lgn build sa n 1,注意n 1 getheight n n 8 num 注意num陣列最後一位值為0,其它位須大於0 rank rank 0 n ...
利用倍增演算法的字尾陣列
仍然不是很懂,貼篇文章放在這兒希望有朝一日能頓悟吧。老天,乙個字尾陣列不知道看了多少天,最後終於還是看懂了啊!最關鍵的就是一會兒下標表示排名,一會用數值表示排名繞死人了。我不知道手跑了多少次才明白過來。其實我也建議初學者手跑幾遍,但是一定要注意陣列的意義,否則就是無用功。s 輸入的字串,預處理的時候...
字尾陣列倍增演算法模板詳解
2009國家集訓隊 字尾陣列 處理字串的有力工具 羅穗騫 bool cmp int r,int a,int b,int l void init int r,int sa,int n,int m for i 0 i n i rk sa i i int k 0 for i 0 i n 1 h rk i ...