后缀数组原理

一 点睛

在字符串处理中,后缀树和后缀数组都是非常有力的工具,后缀数组是后缀树的一个非常精巧的替代品,比后缀树更容易实现,可以实现后缀树的很多功能,时间复杂度也不逊色,比后缀树所占用的空间也小很多。

一个长度为 8 的字符串 aabaaaab,一共有 8 个后缀,后缀的编号是后缀在原串中的起始位置。把 8 个后缀按字典序升序排序。

二 相关概念

1 后缀

指从某个位置开始到字符串末位的一个特殊子串。字符串 s 从第 i 个字符开始的后缀被表示为 Suffix(i),也可以称为下标为 i 的后缀。字符串 s='aabaaaab',其所有的后缀如下:

Suffix(0)="aabaaaab"

Suffix(1)="abaaaab"

Suffix(2)="baaaab"

Suffix(3)="aaaab"

Suffix(4)="aaab"

Suffix(5)="aab"

Suffix(6)="ab"

Suffix(7)="b"

2 后缀数组

将所有的后缀都从小到大排序,将排好序的后缀下标 i 放入数组中,该数组就叫作后缀数组。将上面所有后缀都按字典序排序之后,取其下标 i,即可得到后缀数组。

Suffix(3)="aaaab"

Suffix(4)="aaab"

Suffix(5)="aab"

Suffix(0)="aabaaaab"

Suffix(6)="ab"

Suffix(1)="abaaaab"

Suffix(7)="b"

Suffix(2)="baaaab"

后缀数组SA={3,4,5,0,6,1,7,2}

3 排名数组

排名数组指下标为 i 的后缀排序后的名次,例如在上面例子中排序后的下标和名次。若 rank[i]=num,则下标为 i 的后缀排序后的名次为 num: 

名次 下标  后缀

num  i    Suffix(i)

1    3    aaaab

2    4    aaab

3    5    aab

4    0    aabaaaab

5    6    ab

6    1    abaaaab

7    7    b

8    2    baaaab

下标为 3 的后缀,排名第 1;排名第 1 的后缀,下标为 3,即 SA[1]=3。排名数组和后缀数组是互逆的,可以来回转换。

4 高度数组

height[i] = lcp(sa[i],sa[i-1])

第 i 名后缀与第 i-1 名后缀的最长公共前缀的长度。

height[2]=lcp(5,4)=3

height[3]=lcp(6,5)=2

height[4]=lcp(1,6)=3

......

高度数组表示两个后缀的相似度,排序相邻的两个后缀相似度最高。

后缀 i 的前邻后缀一定是 sa[rk[i]-1],因为 i = sa[rk[i]],i 的排名为 rk[i],排名减1取 sa 即得。

sa[rk[1]-1]=sa[4-1]=sa[3]=6。

定理:

height[rk[i]]>=height[rk[i-1]]-1

三 后缀数组的构建思路

1 将字符串 s(aabaaaab)从每个下标开始长度为 1 的子串进行排名,直接将每个字符转换成 s[i]-'a'+1即可,如下图所示。

2 求解长度为 2 的子串排名。

将上一次 rank 值的第 i 个和 第 i+1 个结合,相对于得到长度为 2 的子串的每个位置排名,然后排序,即可得到长度为 2 的子串排名。

3 求解长度为 2^2 的子串排名。

将上一次 rank 值的第 i 个和第 i+2 个结合,相对于得到长度为 2^2 的子串的每个位置排名,排序后得到长度为 2^2 的子串排名。

4 求解长度为 2^3 的子串排名。

将上一次 rank 值的第 i 个和第 i+4 个结合,相对于得到长度为 2^3 的子串的每个位置排名,排序后得到长度为 2^3 的子串排名。

第 4 步和第 3 步的结果一样,实际上,若在 rank 没有相同值时,就已经得到了后缀排名,就不需要再继续运算了。因为根据字符串比较规则,两个字符串的前几个字符已经分出大小,后面无须判断。

将排名数组转换为后缀数组,排名第1的下标为3,排名第2的下标为4,排名第3的下标为5,排名第4的下标为0,排名第5的下标为6,排名为6的下标为1,排名第7的下标为7,排名第8的下标为2,因此SA[]={3,4,5,0,6,1,7,2}。

四 代码图解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值