后缀数组(下——height与h)

见《上》:https://blog.csdn.net/fengqiyuka/article/details/94589605

背景

  • 没有背景
  • 我们发现,如果只有SA与rank,真是除了求排名什么也做不了。
  • 哈哈哈,其实SA与rank只是铺垫,后缀数组最厉害的地方就要展现——

最长公共前缀

  • 先来一个最简单的问题:给定一个字符串,求出现最少2次的字符串最长长度。
  • 看罢,你喊道——这不是很简单吗?直接 O ( n 3 ) O(n^3) O ( n 2 ) O(n^2) 搞定啊!
  • 少年,你落伍了!现在已经是log的时代!!(好吧是O(n) 的时代)
  • 在机智地把这道题与后缀联系起来之后,我们发现这道题其实就是求后缀之间的最长公共前缀!
  • 例如一个子串在字符串s中的位置分别是 [ a , b ] [a,b] [ c , d ] [c,d] ,那么这个子串其实就是以a为开头的后缀与以c为开头的前缀的公共前缀。
  • 我们发现,之前学过的后缀数组SA与rank,几乎什么用也没有。
  • 于是乎,一个全新的后缀数组登场了!! (好吧是两个)

height与h

  • 首先让我们清楚这两个后缀数组的定义。

  • 定义 L C P ( i , j ) LCP(i,j) 以sa[i]开头的后缀和以sa[j]开头的后缀的最长公共前缀。

  • h e i g h t [ i ] height[i] 指的是排名为i的后缀与排名为i-1的后缀的最长公共前缀,即 L C P ( i 1 , i ) LCP(i-1,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])

  • 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]]

    LCP的性质
    • 重点部分来了,之所以height与h可以快速求出,是因为LCP有很多神奇的性质。
    • a. L C P ( i , j ) > = L C P ( i , k ) LCP(i,j)>=LCP(i,k) ,当 1 < = i < = j < = k < = n 1<=i<=j<=k<=n
    • 我们设 L C P ( i , j ) = p LCP(i,j)=p ,则 s [ i + p ] s [ j + p ] s[i+p] \neq s[j+p] 。因为 i i 的排在 j j 前面,所以 s [ i + p ] < s [ j + p ] s[i+p]<s[j+p] ,又因为 j j k k 前面,若 L C P ( 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) ,通过比较可以的出 k k j j 小,则假设不成立,得证。

    • b. L C P ( j , i ) > = L C P ( k , i ) LCP(j,i)>=LCP(k,i) ,当 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 r a n k [ j ] < r a n k [ i ] rank[j]<rank[i] ,则 r a n k [ j + 1 ] < r a n k [ i + 1 ] rank[j+1]<rank[i+1] ,且 L C P ( r a n k [ j + 1 ] , r a n k [ i + 1 ] ) = r a n k ( [ i ] , r a n k [ j ] ) 1 LCP(rank[j+1],rank[i+1])=rank([i],rank[j])-1
    • 这个其实也是比较显然的。
    • 由已知我们可以得到以i开头后缀与以j开头后缀第一次出现不同的位置在 s [ i + k ] s[i+k] s [ j + k ] s[j+k] 处,则 k > = 1 k>=1 ,因为 r a n k [ j ] < r a n k [ i ] rank[j]<rank[i] ,所以 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]
    • 后面这个等式就不用说了吧…

终极性质

  • 很好,现在让我们说出height与h最重要的性质:
  • h [ i ] > = h [ i 1 ] 1 h[i]>=h[i-1]-1
  • 首先我们设排在 i 1 i-1 前一位的是 k k ,排在 i i 前一位的是 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 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 ] = 0 h[i-1]=0 ,显然。
  • 第二种, h [ i 1 ] 1 h[i-1] \ge 1 ,则 L C P ( r a n k [ i 1 ] , r a n k [ k ] ) 1 LCP(rank[i-1],rank[k]) \ge 1
  • 由性质c我们可以得到,由于 r a n k [ k ] < r a n k [ 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
  • 因为 r a n k [ j ] = r a n k [ i ] 1 rank[j]=rank[i]-1 ,所以 r a n k [ k + 1 ] < = r a n k [ j ] rank[k+1]<=rank[j] ,有性质 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] ,则 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) ,所以 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 。得证。
  • 综上所述, h [ i ] > = h [ i 1 ] + 1 h[i]>=h[i-1]+1

求法

  • 有了刚才那个性质之后,h数组就很好求了吧!
  • 假设已经知道了 h [ i 1 ] h[i-1] ,我们只要从 h [ i 1 ] 1 h[i-1]-1 开始匹配来求出 h [ i ] h[i] 即可。
  • 求出了h数组,height数组也就很好求了。

刚才那道题

  • 还记得那道题目吗?
  • 给定一个字符串,求出现最少2次的字符串最长长度。
  • 显然求height数组的最大值即可。

代码

  • 没有代码,裸题太不好玩了。
  • 大家可以搜一搜与此有关的题目,大把大把。
发布了58 篇原创文章 · 获赞 12 · 访问量 8556

猜你喜欢

转载自blog.csdn.net/fengqiyuka/article/details/95247518
今日推荐