如果想了解更多內容,歡迎關注我的微信公衆號:信息學競賽從入門到巔峯。
上期我們介紹了後綴數組中代碼最難寫的一部分,今天我們來講解一下後綴數組中最精髓的一部分——height數組的求解。
【進階】字符串問題一大利器——後綴數組詳解(附上sa數組求法的講解)
幾個共識
和之前一樣,爲了後文方便講解,我們先來達成幾個共識。
1、height[i]表示後綴sa[i-1]和後綴sa[i]的最長公共前綴。換句話說,height數組表示排名相鄰的兩個後綴的最長公共前綴。
2、h[i]表達第i個後綴和排名在他之前一位的後綴的最長公共前綴,即
性質及證明
防止證明過程中公式排版出錯,這裏仍然採用圖片的形式講解。
求解height
我們很容易想到一種樸素的暴力算法,直接在每兩個排名相鄰的後綴之間枚舉求解。但是這種算法最壞情況下的複雜度是O(N^2)的,而且完全沒有利用後綴數組的性質。
下面,我們來講解一種時間複雜度爲O(N)的巧妙求法。
利用h數組的性質,我們按照排名的順序來求解height數組。每次先把長度減1後,循環暴力擴展,並且把求出來的h[i]拷貝到height[rank[i]]即可。
由於字符串的長度最大爲N,最多進行N次減1操作,所以總計算次數是O(N)級別的。
Code
void height_get(int *r,int n) {
//r爲字符串原串,n爲字符串長度。
//此處的字符串爲添加最小元素後的字符串。
int k=0;
for (int i=0;i<n;++i)rank[sa[i]]=i;
for (int i=0;i<n;++i)
{
if (k)k--;
int j=sa[rank[i]-1];
while (r[i+k]==r[j+k])k++;
height[rank[i]]=k;
}
}//求最長公共前綴,利用h[i]>=h[i-1]-1
寫在最後
後綴數組算法的重點在於求解sa數組、rank數組和height數組。有了這三個數組,我們就可以在字符串的世界自由玩耍了【滑稽】。