见《上》:https://blog.csdn.net/fengqiyuka/article/details/94589605
背景
- 没有背景
- 我们发现,如果只有SA与rank,真是除了求排名什么也做不了。
- 哈哈哈,其实SA与rank只是铺垫,后缀数组最厉害的地方就要展现——
最长公共前缀
- 先来一个最简单的问题:给定一个字符串,求出现最少2次的字符串最长长度。
- 看罢,你喊道——这不是很简单吗?直接 O ( n 3 ) O(n^3) O(n3)或 O ( n 2 ) O(n^2) O(n2)搞定啊!
- 少年,你落伍了!现在已经是log的时代!!
(好吧是O(n) 的时代) - 在机智地把这道题与后缀联系起来之后,我们发现这道题其实就是求后缀之间的最长公共前缀!
- 例如一个子串在字符串s中的位置分别是 [ a , b ] [a,b] [a,b]和 [ c , d ] [c,d] [c,d],那么这个子串其实就是以a为开头的后缀与以c为开头的前缀的公共前缀。
- 我们发现,之前学过的后缀数组SA与rank,几乎什么用也没有。
- 于是乎,一个全新的后缀数组登场了!!
(好吧是两个)
height与h
-
首先让我们清楚这两个后缀数组的定义。
-
定义 L C P ( i , j ) LCP(i,j) LCP(i,j)为以sa[i]开头的后缀和以sa[j]开头的后缀的最长公共前缀。
-
而 h e i g h t [ i ] height[i] height[i]指的是排名为i的后缀与排名为i-1的后缀的最长公共前缀,即 L C P ( i − 1 , i ) LCP(i-1,i) LCP(i−1,i)。
-
h [ i ] h[i] h[i]指的则是以i为开头的后缀与排名在它前一位的后缀的最长公共前缀,即 L C P ( r a n k [ i ] − 1 , r a n k [ i ] ) LCP(rank[i]-1,rank[i]) LCP(rank[i]−1,rank[i])。
-
h [ i ] h[i] h[i]很绕,必须先弄清楚定义,后面的东西才可以明白。
-
给出两个等式 h e i g h t [ i ] = h [ S A [ i ] ] , h [ i ] = h e i g h t [ r a n k [ i ] ] height[i]=h[SA[i]],h[i]=height[rank[i]] height[i]=h[SA[i]],h[i]=height[rank[i]]。
LCP的性质
- 重点部分来了,之所以height与h可以快速求出,是因为LCP有很多神奇的性质。
- a. L C P ( i , j ) > = L C P ( i , k ) LCP(i,j)>=LCP(i,k) LCP(i,j)>=LCP(i,k),当 1 < = i < = j < = k < = n 1<=i<=j<=k<=n 1<=i<=j<=k<=n。
- 我们设 L C P ( i , j ) = p LCP(i,j)=p LCP(i,j)=p,则 s [ i + p ] ≠ s [ j + p ] s[i+p] \neq s[j+p] s[i+p]=s[j+p]。因为 i i i的排在 j j j前面,所以 s [ i + p ] < s [ j + p ] s[i+p]<s[j+p] s[i+p]<s[j+p],又因为 j j j在 k k k前面,若 L C P ( i , k ) > p LCP(i,k)>p LCP(i,k)>p,则必有 s [ i + l ] = s [ k + l ] ( 0 < = l < = p ) s[i+l] = s[k+l](0<=l<=p) s[i+l]=s[k+l](0<=l<=p),通过比较可以的出 k k k比 j j j小,则假设不成立,得证。
- b. L C P ( j , i ) > = L C P ( k , i ) LCP(j,i)>=LCP(k,i) LCP(j,i)>=LCP(k,i),当 1 < = k < = j < = i < = n 1<=k<=j<=i<=n 1<=k<=j<=i<=n。
- 证明方法类似。
- c.若 L C P ( r a n k [ i ] , r a n k [ j ] ) ≥ 1 LCP(rank[i],rank[j]) \ge 1 LCP(rank[i],rank[j])≥1且 r a n k [ j ] < r a n k [ i ] rank[j]<rank[i] rank[j]<rank[i],则 r a n k [ j + 1 ] < r a n k [ i + 1 ] rank[j+1]<rank[i+1] rank[j+1]<rank[i+1],且 L C P ( r a n k [ j + 1 ] , r a n k [ i + 1 ] ) = L C P ( r a n k [ i ] , r a n k [ j ] ) − 1 LCP(rank[j+1],rank[i+1])=LCP(rank[i],rank[j])-1 LCP(rank[j+1],rank[i+1])=LCP(rank[i],rank[j])−1。
- 这个其实也是比较显然的。
- 由已知我们可以得到以i开头后缀与以j开头后缀第一次出现不同的位置在 s [ i + k ] s[i+k] s[i+k]与 s [ j + k ] s[j+k] s[j+k]处,则 k > = 1 k>=1 k>=1,因为 r a n k [ j ] < r a n k [ i ] rank[j]<rank[i] rank[j]<rank[i],所以 s [ j + k ] < s [ i + k ] s[j+k]<s[i+k] s[j+k]<s[i+k],比较可得 r a n k [ j + 1 ] < r a n k [ i + 1 ] rank[j+1]<rank[i+1] rank[j+1]<rank[i+1]。
- 后面这个等式就不用说了吧…
终极性质
- 很好,现在让我们说出height与h最重要的性质:
- h [ i ] > = h [ i − 1 ] − 1 h[i]>=h[i-1]-1 h[i]>=h[i−1]−1
- 首先我们设排在 i − 1 i-1 i−1前一位的是 k k k,排在 i i i前一位的是 j j j。即 h [ i ] = L C P ( r a n k [ i ] , r a n k [ j ] ) h[i]=LCP(rank[i],rank[j]) h[i]=LCP(rank[i],rank[j]), h [ i − 1 ] = L C P ( r a n k [ i − 1 ] , r a n k [ k ] ) h[i-1]=LCP(rank[i-1],rank[k]) h[i−1]=LCP(rank[i−1],rank[k])。
- 分类讨论模式启动…
- 第一种, h [ i − 1 ] = 0 h[i-1]=0 h[i−1]=0,显然。
- 第二种, h [ i − 1 ] ≥ 1 h[i-1] \ge 1 h[i−1]≥1,则 L C P ( r a n k [ i − 1 ] , r a n k [ k ] ) ≥ 1 LCP(rank[i-1],rank[k]) \ge 1 LCP(rank[i−1],rank[k])≥1。
- 由性质c我们可以得到,由于 r a n k [ k ] < r a n k [ i − 1 ] rank[k]<rank[i-1] rank[k]<rank[i−1],则 r a n k [ k + 1 ] < r a n k [ i ] , L C P ( r a n k [ k + 1 ] , r a n k [ i ] ) = L C P ( r a n k [ k ] , r a n k [ i − 1 ] ) − 1 = h [ i − 1 ] − 1 rank[k+1]<rank[i],LCP(rank[k+1],rank[i])=LCP(rank[k],rank[i-1])-1=h[i-1]-1 rank[k+1]<rank[i],LCP(rank[k+1],rank[i])=LCP(rank[k],rank[i−1])−1=h[i−1]−1。
- 因为 r a n k [ j ] = r a n k [ i ] − 1 rank[j]=rank[i]-1 rank[j]=rank[i]−1,所以 r a n k [ k + 1 ] < = r a n k [ j ] rank[k+1]<=rank[j] rank[k+1]<=rank[j],有性质 b b b可得:设 A = r a n k [ k + 1 ] , B = r a n k [ j ] , C = r a n k [ i ] A=rank[k+1],B=rank[j],C=rank[i] A=rank[k+1],B=rank[j],C=rank[i],则 1 < = A < = B < = C < = n 1<=A<=B<=C<=n 1<=A<=B<=C<=n。
- 所以 L C P ( B , C ) > = L C P ( A , C ) LCP(B,C)>=LCP(A,C) LCP(B,C)>=LCP(A,C),所以 L C P ( r a n k [ j ] , r a n k [ i ] ) > = L C P ( r a n k [ k + 1 ] , r a n k [ i ] ) = h [ i − 1 ] + 1 LCP(rank[j],rank[i])>=LCP(rank[k+1],rank[i])=h[i-1]+1 LCP(rank[j],rank[i])>=LCP(rank[k+1],rank[i])=h[i−1]+1。得证。
- 综上所述, h [ i ] > = h [ i − 1 ] + 1 h[i]>=h[i-1]+1 h[i]>=h[i−1]+1。
求法
- 有了刚才那个性质之后,h数组就很好求了吧!
- 假设已经知道了 h [ i − 1 ] h[i-1] h[i−1],我们只要从 h [ i − 1 ] − 1 h[i-1]-1 h[i−1]−1开始匹配来求出 h [ i ] h[i] h[i]即可。
- 求出了h数组,height数组也就很好求了。
刚才那道题
- 还记得那道题目吗?
- 给定一个字符串,求出现最少2次的字符串最长长度。
- 显然求height数组的最大值即可。
代码
- 没有代码,裸题太不好玩了。
- 大家可以搜一搜与此有关的题目,大把大把。