最近做了些机试题目,有道题目(不重复最长重复子串)测试时没想出有效解法,后来看到后缀数组,额,强大啊。记录之,分享之。有错误的地方,请留言啊,谢谢亲们~~~~~~~~~~~~~~~~~
概念部分,请查看参考资料2、3哦
//for_wind
一、后缀数组
(1)基本概念
1、字符串的大小比较:
关于字符串的大小比较,是指通常所说的 “ 字典顺序 ” 比较。如a<b,aab<ab,a<ab。
注:从字符串的大小比较的定义看,字符串s的所有后缀中任其中一对(u,v)不可能会相等,因为必要条件 len(u) ≠ len(v)不可能满足。所以任一字符串s中有len(s)个互不相同的后缀。我们可以将s的所有后缀排列,利用 后缀数组sa 与 名次数组rank 储存。
2、后缀数组sa:
将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置。
- 简单的记忆就是“排第几的是谁”。
3、名次数组rank:
rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次。则 若 sa[i]=j,则 rank[j]=i。
- 简单的记忆就是“你排第几”。
4、sa和rank的关系
对于 后缀数组sa 与 名次数组rank ,有 rank[ sa[i] ]=i
(这是很重要的一点,通过sa与rank的关系可以求出后缀数组)
- 由此可看出,后缀数组sa 与名次数组rank的关系为互逆关系。
Figure 1字符串aabaaaab的sa数组与rank数组
(2)倍增算法
1、主要思路:
倍增,s[i..i + 2^k − 1]的排名通过s[i..i + 2^(k − 1) − 1]和s[i + 2^(k − 1) − 1..i + 2^k] 的排名得到。
2、简要过程。
略。请参考最下面的参考资料3。嘻嘻。
Figure2倍增算法的计算过程
3、时间复杂度
每一趟的计数排序的时间复杂度是O(n),排序的次数共log n次,总的时间复杂度为O(n log n)。
(3)最长公共前缀:
通常我们需要由rank与sa数组计算出一个辅助工具height数组——最长公共前缀(LCP)。
1、主要思想
height 数组: 定义height[i]=suffix(sa[i-1]) 和 suffix(sa[i]) 的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。
由height数组可得,对于j和k ,不妨设rank