后缀数组(SuffixArray) 学习笔记

后缀数组

    前面有介绍过后缀树,后缀树对于我们针对某些字符串的处理使得如鱼得水,美中不足的是后缀树的代码实现复杂,只能让很多人望而却步。这次我们来介绍后缀树组:一个处理字符串的有力工具,也是一个后缀树的精美替代品,同样可以方便解决很多字符串问题。它比后缀树更加容易实现编码,也可以在不损失效率的情况下实现很多后缀树的功能,占用内存也比后缀树小很多,尤其是在模式匹配数据规模庞大的操作中实用性很高,很多搜索引擎也都在使用这样一个神奇的数据结构。


先来看看几个概念:

1> 假设有一个字符串:S 针对字符串S, Len(s) 表示字符串对应的长度

2>后缀Suffix(i): 对于字符串中的任意一个索引i开始到字符串结束的子串称之为该字符串S的一个后缀。比如suffix(i) = S[i...len(s)].

3>后缀数组SA(i):将一个字符串S的所有后缀串,按照字典顺序依次放入到一个数组中,这个数组表明了S的所有后缀串的字典顺序,这样一个有序的后缀串数组就是后缀数组。后缀数组SA(i)表示排名第i的字符串是谁?当然要注意的是这里的SA(i)的值是一个索引,是第i名的后缀串在原有串的起始索引值。

4>名次数组Rank(i): 名次数组是保存的是suffix(i)这个后缀在所有后缀串中的排名。不难发现名次数组和后缀数组是个互逆的排名。SA数组是表示排第几的是谁,而Rank则表示的是谁排第几。也就是说SA[Rank[i]] = i,从而也就是说在知道任意一个数组的情况下O(n)时间复杂度内快速求得另外一个数组。有了名次数组我们也可以在O(1)时间内求出任意两个后缀的大小关系。

 

如何构造后缀数组:

1> 将字符串S的所有后缀当成独立的字符串进行常规排序,平方级O(n^2)时间复杂度,因为忽略了所有后缀串之间的相互联系,将所有后缀当成独立的字符串进行排序从而构造效率低下,当然你对时间要求没那么高,数据规模没那么大当然可以轻松实现。这也不是本文的重点。

2> 根据罗穗骞的论文我们可以使用倍增算法(Doubling Algorithm),可以再O(nlogn)时间内构造出后缀数组,编码简单易行。

3> 罗穗骞的论文还提供了一种更为高效的构造算法:DC3算法,这是一个优秀的线性算法O(N)时间复杂度内构造后缀数组,编码相对于DA算法复杂。

 

     本文重点描述倍增算法(DA)构造后缀数组,提供的倍增算法来自于罗穗骞的论文所描述的算法,这里仅提供对该算法的一些个人梳理,论文和所有求证过程需要自己去拜读原始论文《后缀数组——处理字符串的有力工具》。

     倍增算法(DA):设字符串长度为n, 为了方便比较大小,可以再字符串的后面添加一个字符,这个字符没有在前面的字符中出现过,而且比前面的字符都要小,通常这个补充字符是0或者$。倍增算法就是用倍增的方法对每个字符开始的长度为2^k的子串进行排序,求出排名rank值。从k=0开始, 每次k加1, 当2^k大于n以后,每个子串开始的长度为2^k的子串便相当于所有的后缀。而且这些子串已经比较出大小了,所有的rank都没有相同的值,这个rank就是最后的结果。每一次排序都利用上一次的2^(k-1)的字符串的rank值, 那么长度为2^k的字符串的rank就可以用两个长度为2^(k-1)的字符串的排名为关键字表示出来,对关键字进行计数排序,便可以得到长度为2^k的字符串的rank。

                         

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值