后缀数组(Suffix Array )

定义说明:

后缀:从字符串的任意一个字符开始一直到最后一个字符所构成的一个字符串

例如:对于字符串"abcdefg","cdefg"、"efg"、"g"都是后缀,"cde"则不是后缀 

在学习后缀数组之前,我们首先要知道后缀数组是什么?

后缀数组:将一个字符串的所有后缀按照字典序从小到大进行排序得到的一个数组

给定字符串str,长度为n,位置编号从1到n

Suffix数组(string类型):表示字符串str的后缀

Suffix[i]:字符串str从位置i到位置n(即字符串结尾)构成的一个字符串

后缀i表示Suffix[i];排序是指字符串按照字典序从小到大进行排序

Sa数组(int类型):即所求的后缀数组,也即Suffix数组排序后得到的一个数组(这个数组一般是整数型数组,而不是string类型数组,因为对于一个后缀我们可以用后缀的起始位置pos来表示这个后缀,通过Suffix[pos]就能得到这个后缀)

Sa[i]=x:表示字符串str第i小的后缀是Suffix[x]

Rank数组(int类型):表示后缀字符串排序后是第几

Rank[i]=x:表示后缀i排序后是第x小,也即Sa[x]=i

构造

怎么构造后缀数组呢?暴力的方法是将所有后缀直接进行快速排序,快排的时间复杂度是O(n*logn),因为是对字符串进行排序,排序过程中字符串之间的比较花费的时间不是O(1),而是O(n),所以总的时间复杂度是O(n*n*logn);这样的时间复杂度是我们不能接受的,下面介绍的算法构造后缀数组的时间复杂度只需要O(n*logn)

倍增算法

思想:不断给后缀排序(并不是真正的排序),每次排序后计算后缀的次序号,直到每个后缀的次序号都不同

第一次排序:将每个后缀的前一个字符进行排序

第二次排序:将每个后缀的前两个字符进行排序

第三次排序:将每个后缀的前四个字符进行排序

………………………………………………

第k次排序:将每个后缀的前(2^(k-1))个字符进行排序

要进行多少次排序呢?最多进行logn次排序就能使每个后缀的次序号不同,时间复杂度O(logn)

(重点)怎么计算排序后的次序号?

后缀k的前4个字符是由后缀k的前2个字符和后缀k+2的前两个字符组成,因为每个后缀的前2个字符的次序号已经计算出来了,所以计算任一后缀k的前4个字符的次序号z可以通过比较后缀k的前2个字符的次序号x和后缀k+2的前两个字符的次序号y;将这两个次序号x,y看成一个二元组(x,y),对于计算任一后缀i的前4个字符的次序号zi都有一个二元组(xi,yi),通过二元组的比较就可以得到后缀的前4个字符的次序号。不难发现对于计算后缀前2^n个字符的次序号也适用,只需要从低到高递推即可。

二元组比较规则是:x小则z小;若x相同,y小则z小,若x,y都相同则z相同(很容易理解,因为前面的决定权更大)

图有助于理解:

image

看到这应该已经差不多理解倍增算法了,但是怎么进行排序呢?

限于篇幅,就将这两种排序方法写在其他博客上了

后缀数组的快速排序实现

后缀数组的基数排序实现

 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值