模板奉上算法
int rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++) //求h[i] = height[rank[i]];
; return; }
概念:數組
(1)height 數組:定義height[i]=suffix(SA[i-1])和suffix(SA[i])的最長公共前綴,也就是排名相鄰的兩個後綴的最長公共前綴的長度 。函數
(2)h[i]=height[rank[i]],也就是suffix(i)和排序後在它前一名的後綴的最長公共前綴的長度。spa
(3)函數lcp(u,v)=max{i|u=v},也就是從頭開始順次比較u和v的對應字符,對應字符持續相等的最大位置,稱爲這兩個字符串u,v的最長公共前綴的長度。code
(4)LCP(i,j):對正整數i,j 定義LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j]),其中i,j 均爲1至n的整數。LCP(i,j)也就是後綴數組中第i個和第j個後綴的最長公共前綴的長度。blog
性質:排序
(1)LCP(i,j)=min{height[k]|i+1≤k≤j},也就是說,計算LCP(i,j)等同於詢問一維數組height[] 中下標在i+1 到j 範圍內的全部元素的最小值。字符串
(2)對於i>1 且Rank[i]>1,必定有h[i]≥h[i-1]-1。(這條性質要好好理解!)模板
證實:設suffix(k)是排在suffix(i-1)前一名的後綴,它們的最長公共前綴是h[i-1]。class
那麼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)。
即:
rank[i-1] = q-1 suffix(k): rabaa
rank[i-1] = q suffix(i-1): racadabrabaa h[i-1] = 2;
......
rank[k-1] = p-1 suffix(k-1): abaa
rank[i] = p suffix(i): acadabrabaa h[i] = 1 (h[i] >= h[i-1]-1 = 1;)
計算數組h[]
能夠令i從1循環到n(此循環中i的意義爲suffix(i))按照以下方法依次算出h[i]:
若 Rank[i]=1,則h[i]=0。字符比較次數爲0。
若i=1或者h[i-1]≤1,則直接將Suffix(i)和Suffix(Rank[i]-1)從第一個字符開始依次比較直到有字符不相同,由此計算出h[i]。字符比較次數爲h[i]+1,不超過h[i]-h[i-1]+2。
不然,說明i>1,Rank[i]>1,h[i-1]>1,根據性質2,Suffix(i)和Suffix(Rank[i]-1)至少有前h[i-1]-1 個字符是相同的,因而字符比較能夠從h[i-1]開始,直到某個字符不相同,由此計算出h[i]。字符比較次數爲h[i]-h[i-1]+2。
可求得最後算法複雜度爲O(n)。