關於後綴數組的一點想法
後綴數組大概就是用後綴排名來搞一些事情,因為字符串中的每一個子串都可看做某一後綴的前綴
可用倍增法求出後綴排名
一、數組意義(對於字符串 s)
sa[i]:排名為i的後綴的開頭在s中的位置
height[i]:排名為i的後綴和排名為i-1的後綴的LCP(最長公共前綴)
c[]:用於基數排序,統計前綴和
rank[i]:以s[i]開頭的後綴的排名 顯然 rank[sa[i]]=i sa[rank[i]]=i
二、求sa[]具體思路
1.用倍增法構造第一、第二關鍵詞,第一關鍵詞小的排在前,第一關鍵詞相同的 第二關鍵詞小的排在前。
2.優化:如果後綴長度枚舉到某一大小時,每個後綴的排名彼此不同,那麽可以直接退出,道理很顯然
三、求height[]具體思路
先求出rank[i]
看height[]的定義,知道應取suffix(sa[rank[i-1]])和suffix(i)的LCP
只要找到suffix(sa[rank[i-1]])的開頭j,暴力枚舉便可
此處有一個小優化(詳情參見http://www.cnblogs.com/LLGemini/p/4771235.html)
h[]即為height[]
對於i>1 且Rank[i]>1,一定有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)。
四、註意事項
構建sa[]時,傳4個參進入函數,設原字符串為s,設s的長度為n,s中最大字符的大小為m
build_sa(s[],sa[],n+1,m)
傳n+1而不傳n的原因是在s的末尾補上了一個 “0”
原因:防止數組越界
for(int i=1;i<n;i++)x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
如果 x[idx1]==x[idx2](註意idx1!=idx2), 說明以 idx1或 idx2
開頭的長度為 len
的字符串肯定不包括字符 x[n-1]
, 所以調用變量 sa[idx1+len]
和 sa[idx2+len]
不會導致數組越界, 這樣就不需要做特殊判斷.
完美解決了!
代碼:
1 int sa[N],rk[N],h[N],c[N],r[N],wa[N],wb[N],sp[N],n,k; 2 3 void get_sa(int *r,int *sa,int n,int m){ 4 int *x=wa,*y=wb;//都是輔助變量 5 for(int i=0;i<n;i++)c[x[i]=r[i]]++; 6 for(int i=1;i<m;i++)c[i]+=c[i-1]; 7 for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 8 for(int k=1;k<=n;k<<=1){ 9 int p=0; 10 for(int i=n-k;i<n;i++)y[p++]=i; 11 for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; 12 13 for(int i=0;i<m;i++)c[i]=0; 14 for(int i=0;i<n;i++)c[x[i]]++; 15 for(int i=1;i<m;i++)c[i]+=c[i-1]; 16 for(int i=n-1;~i;i--)sa[--c[x[y[i]]]]=y[i]; 17 18 swap(x,y);//x,y是指針,直接互換 19 p=1;x[sa[0]]=0; 20 for(int i=1;i<n;i++)x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 21 if(p>=n)break; 22 m=p;//優化:最多有p個元素,下一次最大值為p 23 } 24 } 25 26 void get_h(){ 27 int k=0,mh=-1; 28 for(int i=0;i<n;i++)rk[sa[i]]=i; 29 for(int i=0;i<n;i++){ 30 if(k)k--; 31 int j=sa[rk[i]-1]; 32 while(r[i+k]==r[j+k])k++; 33 h[rk[i]]=k; 34 } 35 }View Code
2017-06-02 20:58:43
關於後綴數組的一點想法