Skip to content

后缀数组

复制本地路径 | 在线编辑

重要的是使用场景,而非原理(不过原理也很简单)。

简介

设字符串:S = ababa

构造结构

所有后缀为:

0: ababa
1: baba
2: aba
3: ba
4: a

按字典序排序(得到后缀数组 SA),字典序从小到大排:

4: a
2: aba
0: ababa
3: ba
1: baba

所以后缀数组 SA 就是这些后缀的起始下标

SA = [4, 2, 0, 3, 1]

字符串匹配

假设我们要查找模式串:P = aba

关键性质:如果 PS 中出现,那么 P 一定是某个后缀的前缀务必理解这句话,这是核心思想。

使用二分查找,根据 SA 找出字典序排序之后的字符串,每次比较 P 和字符串前缀:

  • 下界:第一个 ≥ aba 的后缀 → 下标 2
  • 上界:最后一个 ≤ aba 的后缀 → 下标 0

所以匹配位置是: 2 和 0

总结

二分查找 + 前缀比较

时间复杂度:

  • 预处理 SA:O(n) 或 O(n log n)
  • 单次匹配:O(|P| log n)

适合:多次查询、大数据量、多模式匹配

场景

更重要的是使用场景,重点在于他和普通的字符串匹配优势在哪里:

  1. 多次查询:预处理 S 之后,每次查询时间复杂度为 O(|P| log n),而普通字符串匹配每次查询时间复杂度为 O(n)。
  2. 匹配最长前缀:这个需要再加一个数组记录,不过不细谈了。

那很显然了,这种结构很适合在大数据上使用,相当于空间换时间。一次预处理之后,以后查询都会很快。比如生物信息学中:

基因组快速匹配。实验测得的基因序列,匹配人类基因组中哪个位置。由于人类基因组很大,所以普通的字符串匹配,每次都会耗时。所以大家就对人类基因组建立一个后缀数组,以后用的时候就下载这个文件,然后用它进行匹配。

Comments