字尾陣列複習小記

2021-07-09 20:10:34 字數 1634 閱讀 5777

字尾陣列,顧名思義就是處理字尾的陣列。例如daabbc的字尾:daabbc,aabbc,abbc,bbc,bc,c六個字尾。

——>定義sa[i]為排名第i個的字尾的第乙個字元在原字串中的序號。如上面的sa[1]=2,因為字尾從序號2開始的aabbc排第乙個。

——>定義rank[i]為序號從i開始的字尾排第幾個。如上面的rank[1]=6,因為序號從1開始的daabbc排名第六個。有性質:rank[sa[i]]=i,sa[rank[i]]=i。

如何快速求得sa(因為根據性質,知道sa就知道rank),o(n)的方法dc3,o(n log n)的方法倍增演算法。

因為大部分題目倍增演算法就綽綽有餘了。首先給原串中每乙個字元排序:4,1,1,2,2,3(d,a,a,b,b,c),然後第一次合併隔0個合併:41,11,12,22,23,30;然後簡化:6,1,2,3,4,5;第二次隔乙個合併:62,13,24,35,40,50,然後簡化:6,1,2,3,4,5,然後隔兩個合併,然後隔四個合併,八個,十六個,直到大於n為止,道理很顯然。由於空間足夠,用o(n)的基數排序。是個二元組排序。

code

void getsa()

}

處理完sa和rank之後,才是字尾陣列的核心部分。

——>定義陣列height[i],表示排名已第i位的字尾與排名第i-1位的字尾的公共字首的長度。如上面height[4]=1,因為bbc和bc的公共字首的長度為1。

但是如何快速的求height[i],現在引進乙個陣列h[i]=height[rank[i]],表示當前這個以序號i開頭的字尾與排名前乙個的字尾的公共字首的長度。

有乙個重要的性質:h[i]>=h[i-1]-1。證明:如h[i-1]>=1(h[i-1]>=0很顯然)設s[k-1..k-1+h[i-1]-1]=s[i-1..i-1+h[i-1]-1],所以s[k…k+h[i-1]-1]=s[i…i+h[i-1]-1]所以h[i]至少為h[i-1]-1。

code

fo(i,1,n)

以上都是建立字尾陣列的過程

用height陣列可以直接處理出,連著排名的兩個字尾的最長公共字首,所以求最大值就是字尾的最長公共字首和任意兩個字尾的最長公共字首(可重疊的最長重複子串)。

給height的值按k分一下塊,可以求出重複次數至少為k的子串個數。如0,2,1,2,3,1,1,2,按2分塊為[1,2],[3,4,5],[6],[7,8],例如[3,4,5]表示排名3到5的最長公共字首長度至少為2。如果要看不可重疊的重複k次子串,就加乙個二分,再看每個塊中的sa值的最大值和最小值之差是否不小於k[可重疊的很顯然]。

如果要判回文串,就把串倒過來中間加個『#』,『¥』,『$』之類的接起來,求一下height,窮舉每一位,以這一位為中心,時效o(n log n)。

求不同的子串的個數,按照sa的順序逐個加入子串,然後會貢獻出n-sa[i]+1個新的字首,因為有height[i]個相同的,再減去height[i]即可,道理很顯然,這個跟上乙個不同的字首,肯定與上上個以及之前的不同。

多子串問題,大多都只要連起來,再應用上面的即可。

字尾陣列複習小記

定義 suf i 表示以i為開頭的字尾 rank i 表示suf i 的排名,sa i 表示排名為i的字尾 height i 表示sa i 和sa i 1 的lcp h i 表示suf i 和suf sa rank i 1 的lcp sa rank i i,所以只要能求出rank,就可以求sa 倍增...

字尾陣列小記

sa i 表示第 i 小的字尾對應原串的位置 rk i 表示第 i 個字尾的排名 x i 表示第 i 個字尾的第一關鍵字排名,即當前的 rk i y i 表示第 i 小的第二關鍵字對應的第幾個字尾 c i 是乙個計數陣列,用於基數排序用 考慮倍增,每次從 2 k 轉移到 2 可以發現每個 2 串可以...

字尾陣列複習

一下排名均是在字典序下的排名 sa i 排名為 i 的字尾的編號 rank i 第 i 個字尾串的排名 有 rank sa i i 和 sa rank i i height i 排名為 i 的字尾和排名為 i 1 的字尾的最長公共字首 模板 include include include using...