跳转至

后缀数组

一些约定

字符串下标从 0 开始。

后缀 i 表示以下标 i 的字符开始的后缀。

基本概念

后缀数组(Suffix Array)主要是两个数组:sark

其中,sa 为所有后缀按字符串序的升序排列,rk[i] 表示后缀 isa 中的下标。

生成方法

朴素 O(n^2 \log n) 做法

基于字符串比较的朴素排序实现,其中比价两个字符串的时间是 O(n) 的,故排序总时间是 O(n^2 \log n)

基于倍增的 O(n \log^2 n) 做法

一句话:倍增子串的长度上限,维护名次数组 rk,直到长度上限达到 n

该过程进行 \log n 次排序,每次排序的时间复杂度为 O(n \log n)

  • 初始长度上限为 1,对每个字符进行排序,得到名词数组 rk_1

  • 假设我们已经知道了长度上限为 w 的子串排名 rk_w,则二元组序列 p[i] = (rk_w[i], rk_w[i + w]) 排序得到的名词数组即为长度上限为 2w 的子串排名 rk_{2w}
    :若第二关键字不存在(i + w 越界)则取 -1 即可。

  • 循环执行上一步直到长度上限大于等于原字符串长度 n

引入基数排序和计数排序优化到 O(n \log n)

在基于倍增的 O(n \log^2 n) 做法中,单次排序的复杂度为 O(n \log n)。如果能 O(n) 排序,就能将总复杂度优化到 O(n \log n)

由于单次排序的过程中关键字是排名,值域为 O(n),并且是一个双关键字排序,可以使用基数排序优化至 O(n)

常数优化

第二关键字无需计数排序

优化计数排序的值域

缓存 rk[id[i]],减少不连续内存访问

cmp函数来计算是否重复

一些应用

Height数组

Height数组的应用