字尾陣列是處理字串的有力工具。
sa儲存乙個字串按字典序排列的字尾,如圖
rank陣列儲存字尾i的名次,就是把sa反過來,上圖中
rank[1]==2,rank[2]==8
…
height陣列儲存相鄰兩個sa字尾之間公共字首的長度,如圖
思路:用倍增的方法對每個字元開始的長度為2可以求出任意兩個字尾的最長公共字首。k2^k
2k子字串進行排序,求出排名,即 rank 值。k從0開始,每次加,當2
k2^k
2k大於n以後,每個字元開始的長度為2
k2^k
2k的子字串便相當於所有的字尾。並且這些子字串都一定已經比較出大小,即rank值中沒有相同的值,那麼此時的rank值就是最後的結果。每一次排序都利用上次長度為2k−
12^2k−1
的字串的rank值,那麼長度為2
k2^k
2k的字串就可以用兩個長度為2k−
12^2k−1
的字串的名排作為關鍵字表示,然後進行基數排序,便得出了長度為2
k2^k
2k的字串的rank值。
性質1字尾(j)和字尾(k)的最長公共字首為height[rank[j]+1],height[rank[j]+2],height[rank[j]+3],…,height[rank[k]]
中的最小值。
解釋:
首先這些字尾都是按照字典序排列過的,也就是說當第k位為a時,下乙個字尾第k位變成了b,那麼第k位以後就永遠不會變回a了。那麼height區間最小值意思就是在這個區間內,最靠前的變化位。如上圖,最小值1是因為第4排第2位的a變成了b,使得我們要求的兩個字尾的第二位也肯定不一樣,所以他們的最長公共字首為1。
首先得理解乙個性質
性質2height[rank[i]]>=height[rank[i-1]]-1
。
解釋:如下圖,紅色代表字尾(i-1),深藍色代表字尾(i),黃色代表字尾(k),即排名在紅色前面的那乙個,深綠色為它們的最長公共字首,即height[rank[i-1]]
。那麼必定有乙個字尾(k+1)淺藍色,和深藍色的最長公共字首為height[rank[i-1]]
,即淺綠色(比深綠色少一格)。又因為性質1,所以淺藍色與深藍色排名的中間的height值最小為淺綠色長度,所以height[rank[i]]
(深藍色與他前一名的最長公共字首)一定是≥淺綠色的,即height[rank[i]]≥height[rank[i-1]]-1
。
利用這個性質,height就可以用乙個標記記錄height[rank[i-1]]
,減少列舉次數。
集訓隊**的**太難理解了,這裡是我的**:
這份**較長,但便於初學者理解,後面第二篇為簡化版
#include
#include
#define maxn 2005
#define max_num 256
char s[maxn]
;namespace suffixarray
for(
int i=
1;i)//基數排序後半段關鍵字
for(
int i=n-
1;i>=
0;i--
) tsa[
--cntb[b[i]]]
=i;//在後半段的基礎上基數排序前半段關鍵字
for(
int i=n-
1;i>=
0;i--
) sa[
--cnta[a[tsa[i]]]
]=tsa[i]
;//處理重複rank值
rank[sa[0]
]=0;
for(
int i=
1;i) rank[sa[i]
]=rank[sa[i-1]
]+(a[sa[i]
]!=a[sa[i-1]
]||b[sa[i]
]!=b[sa[i-1]
]);}
}void
getheight
(char str,
int n,
int sa,
int rank,
int height)
}}int r[maxn]
,sa[maxn]
,h[maxn]
;int
main()
printf
("\n");
for(
int i=
2;i<=n;i++
)printf
("hight[%d~%d]=%d\n"
,i-1
,i,h[i]);
return0;
}
簡化版**,效率高,**複雜度更低,需利用乙個性質
#include
#include
#include
using
namespace std;
const
int maxn=
2005
;int n;
char str[maxn]
;int sa[maxn]
,rk[maxn]
,h[maxn]
;int cnt[maxn]
,tsa[maxn]
,trk[maxn]
;void
getsa()
}void
geth()
}int
main()
printf
("\n");
for(
int i=
1;i)printf
("hight[%d~%d]=%d\n"
,i,i+
1,h[i]);
return0;
}
至少是我錯過的。。。 Suffix Array 字尾陣列
顧名思義,suffixarray 以下有時簡稱sa 和字串的字尾有關。字尾 字串中某個位置一直到結尾的子串。sa中討論包括了原串和空串 所以共有len 1個字尾。字尾陣列 字串的所有字尾組成的按字典序從小到大排好的陣列。由於sa中記錄的都是字串的字尾,所以sa只需要記錄其表示的字尾的起始位置。由於比...
字尾陣列suffix array
倍增演算法,時間複雜度o nlogn sa從小到大儲存相對大小的下標 理解lsd,x陣列,sa陣列 char s maxn int sa maxn t maxn t2 maxn c maxn n void build sa int m void build sa int m int cmp suff...
字尾陣列 Suffix Array
sa是一種解決多模板匹配問題的演算法。大致就是將字尾處理出來然後按照字典序排個序。時間主要浪費在排序上。sa陣列sa i 表示rk為i的字尾的開始位置。rk陣列rk i 表示以i位置開始的字尾的rank為多少。基數排序 先排個位,然後十位依次往下,穩定演算法。const int n 1e6 5 開二...