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

见《上》: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(i1,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[i1]1
  • 首先我们设排在 i − 1 i-1 i1前一位的是 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[i1]=LCP(rank[i1],rank[k])
  • 分类讨论模式启动…
  • 第一种, h [ i − 1 ] = 0 h[i-1]=0 h[i1]=0,显然。
  • 第二种, h [ i − 1 ] ≥ 1 h[i-1] \ge 1 h[i1]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[i1],rank[k])1
  • 由性质c我们可以得到,由于 r a n k [ k ] < r a n k [ i − 1 ] rank[k]<rank[i-1] rank[k]<rank[i1],则 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[i1])1=h[i1]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[i1]+1。得证。
  • 综上所述, h [ i ] > = h [ i − 1 ] + 1 h[i]>=h[i-1]+1 h[i]>=h[i1]+1
求法
  • 有了刚才那个性质之后,h数组就很好求了吧!
  • 假设已经知道了 h [ i − 1 ] h[i-1] h[i1],我们只要从 h [ i − 1 ] − 1 h[i-1]-1 h[i1]1开始匹配来求出 h [ i ] h[i] h[i]即可。
  • 求出了h数组,height数组也就很好求了。
刚才那道题
  • 还记得那道题目吗?
  • 给定一个字符串,求出现最少2次的字符串最长长度。
  • 显然求height数组的最大值即可。
代码
  • 没有代码,裸题太不好玩了。
  • 大家可以搜一搜与此有关的题目,大把大把。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值