本篇博文同时也作为 WC2021 Day2 的附文。
后缀数组
定义
后缀是什么?(suffix_i = s_{i cdots |s|})。
后缀数组包括 (sa_i, rk_i)。分别表示将 (s) 的所有后缀排序后,排名第 (i) 小的后缀的起始位置,和起始位置在 (i) 上的后缀的排名。
注:这里的“排名”指的是对这些后缀按照字典序排序后的排名。如果现在还不清楚什么是字典序,请自行搜索。
在阅读接下来的内容之前,请务必清楚理解 (sa_i) 和 (rk_i) 的含义,否则会导致接下来的内容理解困难。
为了协助大家理解这两个数组的含义,博主在这里举出一个例子。
这是一个字符串 (S: ext{aabb})
为便于记录,我用一个二元组表示 (S) 的一个后缀极其起始位置,那么这个字符串的后缀所代表的二元组有:
[{left( ext{aabb}, 1
ight), left( ext{abb}, 2
ight), left( ext{bb}, 3
ight), left( ext{b}, 4
ight)}
]
将所有的后缀按照字典序排序,即:
[{left( ext{aabb}, 1
ight), left( ext{abb}, 2
ight), left( ext{b}, 4
ight), left( ext{bb}, 3
ight)}
]
回想之前的定义,(sa_i) 表示的是“排名为 (i) 的后缀的起始位置”。故 (sa) 数组为:({1, 2, 4, 3}),(rk_i) 表示的是 “起始位置为 (i) 的后缀的排名”。故 (rk) 数组为 ({1, 2, 4, 3})
emm 貌似这个例子举的不太好……
构造
倍增法构造 SA
直接找出所有后缀进行排序复杂度显然是 (mathcal Oleft(n^2 ight)) 的,我们需要找到一种更快的方式构造后缀数组。
后缀自动机
构建 SAM
采用“增量法”,利用 (S) 的 SAM 构建出 (S + c) 的 SAM。
其中 (S) 是一个字符串,(c) 是一个字符,(+) 表示连接运算。