后缀数组(SA)

约定

后缀数组

$\mathrm{sa}[i]$ 表示将所有后缀排序后第 $i$ 小的后缀的编号。$\mathrm{rk}[i]$ 表示后缀 $i$ 的排名。

性质:$\mathrm{sa}[\mathrm{rk}[i]]=\mathrm{rk}[\mathrm{sa}[i]]=i$。

求法 1:直接排序,$O(n^2 \log n)$

求法 2:将每个后缀插入到 Trie 上,$O(n^2)$

求法 3:倍增 + 快速排序,$O(n \log^2 n)$

先对每个长度为 $1$ 的子串进行排序。

令 $\mathrm{rk}_w[i]$ 表示长度为 $w$(结尾被截断的除外)的子串 $s[i \ldots \min\{i+w-1,n\}]$ 在 $\{s[i \ldots \min\{i+w-1,n\}]|s \in [1,n]\}$ 中的排名。

假设现在已知 $\mathrm{rk}_w$ 的值,要倍增以求出 $\mathrm{rk}_{2w}$ 的值。以 $\mathrm{rk}_w[i]$ 为第一关键字,以 $\mathrm{rk}_w[i+w]$ 为第二关键字(如果 $i+w>n$,则令 $\mathrm{rk}_w[i+w]=-\infty$),使用快速排序。总共倍增 $O(\log n)$ 次,每次是 $O(n \log n)$,总时间复杂度为 $O(n \log^2 n)$

提交记录(Luogu) 提交记录(LOJ) 备份

求法 4:倍增 + 基数排序,$O(n \log n)$

将前面使用的快速排序改为基数排序,对排名(值域为 $n$)进行双关键字排序,单次排序的时间复杂度为 $O(n)$,时间复杂度为 $O(n \log n)$。

提交记录(Luogu) 提交记录(LOJ) 备份

求法 5:SA-IS 算法,$\Theta(n)$

可以参考 诱导排序与 SA-IS 算法

求法 6:DC3 算法,$O(n)$

可以参考 [2009]后缀数组——处理字符串的有力工具 by. 罗穗骞

$\mathrm{height}$ 数组

最长公共前缀(LCP)

定义

两个字符串 $S$ 和 $T$ 的 LCP 就是最大的 $x$($x \le \min\{|S|,|T|\}$)使得 $\forall i \in [1,x],S_i=T_i$。

下文中以 $\operatorname{lcp}(i,j)$ 表示后缀 $i$ 和后缀 $j$ 的最长公共前缀(的长度)。

性质

LCP Lemma

对于任意的 $1 \le \mathrm{rk}[i]<\mathrm{rk}[j]<\mathrm{rk}[k] \le n$,$\operatorname{lcp}(i,k)=\min\{\operatorname{lcp}(i,j),\operatorname{lcp}(j,k)\}$。

证明:设 $x=\min\{\operatorname{lcp}(i,j),\operatorname{lcp}(j,k)\}$,由定义得,后缀 $i$ 和后缀 $j$ 的前 $x$ 个字符相等,后缀 $j$ 和后缀 $k$ 的前 $x$ 个字符相等,那么后缀 $i$ 和后缀 $k$ 的前 $k$ 个字符相等,即 $\operatorname{lcp}(i,k) \ge x$。

接下来证明 $\operatorname{lcp}(i,k)=x$。用反证法,如果 $\operatorname{lcp}(i,k)=y>x$,那么后缀 $i$ 和后缀 $k$ 的第 $x+1$ 个字符相等,因为 $\mathrm{rk}[i]<\mathrm{rk}[j]<\mathrm{rk}[k]$,所以后缀 $i$、后缀 $j$ 和后缀 $k$ 的第 $x+1$ 个字符相等,矛盾。

LCP Theorem

对于任意的 $\mathrm{rk}[i]<\mathrm{rk}[j]$,$\operatorname{lcp}(i,j)=\min\limits_{\mathrm{rk}[i]<\mathrm{rk}[k] \le \mathrm{rk}[j]}\{\operatorname{lcp}(k-1,k)\}$。

证明:用 LCP Lemma 归纳证明即可。

$\mathrm{height}$ 数组

$\mathrm{height}[i]=\operatorname{lcp}(\mathrm{sa}[i],\mathrm{sa}[i-1])$,即第 $i$ 名的后缀与它前一名的后缀的最长公共前缀。特别地,$\mathrm{height}[1]=0$。

引理:$\mathrm{height}[\mathrm{rk}[i]] \ge \mathrm{height}[\mathrm{rk}[i-1]]-1$

证明:

线性求法

$k$ 的最大值为 $n$,最多减小 $n$ 次,时间复杂度为 $O(n)$。

for(int i=1,k=0;i<=n;i++){
	if(k)k--;
	while(s[i+k]==s[sa[rk[i]-1]+k])k++;
	ht[rk[i]]=k;
}

例题

名称 编号 备注 题解
最长公共子串
本质不同的子串数量
Minimal String Xoration CF1654F 考虑下标异或的性质,用倍增求后缀数组的方法来做 提交记录 备份
差异 AHOI2013D2T3 后缀数组,栈,$\mathrm{height}$ 数组 提交记录 备份
后缀数组,枚举长度 $i$ 并对应地设立 $\lfloor \dfrac{n}{i} \rfloor$ 个关键点,
求出相邻两个关键点之间的 LCP、LCS。时间复杂度为 $O(n \log n)$
Annihilate Luogu P5028 给出 $n$ 个字符串,求出字符串两两最长公共子串长度。保证 $n \le 50$,$|S| \le 10^6$。
把所有字符串用特殊符号全部连起来,求出后缀数组和 $\mathrm{height}$ 数组。
提交记录 备份
品酒大会 NOI2015D2T2 给定串 $S$,求 $\forall i \in [0,n)$ 求有多少对后缀 $\mathrm{suf}_x$、$\mathrm{suf}_y$ 满足 $|\operatorname{lcp}(\mathrm{suf}_x,\mathrm{suf}_y)| \ge i$,
以及满足条件的两个后缀的权值 $a_i$ 乘积的最大值。
后缀数组,并查集
提交记录 备份
[ONTAK2015] Tasowanie Luogu P8023 给定两个数字串 $A$ 和 $B$,通过将 $A$ 和 $B$ 进行二路归并得到一个新的数字串 $T$,请找到字典序最小的 $T$。
后缀数组,贪心,据说,“严格证明可以使用反序后的 Lyndon 划分”。
提交记录 备份
多次询问区间 $[l_i,r_i]$ 的至少出现 $2$ 次的最长子串长度
Musical Theme POJ 1743 不可重叠最长重复子串
Milk Patterns POJ 3261 可重叠的出现 $K$ 次的最长重复子串
Repeats SPOJ REPEATS 求重复次数最多的连续重复子串的重复次数