原理
后缀自动机(Suffix Automaton,简称SAM)是一个能解决许多字符串相关问题的有力的数据结构。举几个例子
- 一个字符串是否出现在另一个字符串中
- 一个字符串包含的各不相同的子串数目
查询一个字符串在另一个字符串中的出现次数
一个字符串在另一个字符串中第一次出现位置或者所有出现位置
- 求两个或多个字符串的最长公共子串
上面这几个例子在构建好SAM之后都可以在线性时间内解决
具体的原理可以参考这篇文章1,里面不仅给出了算法流程还给出了算法的正确性证明.
1. https://oi-wiki.org/string/sam/ ↩
实现
首先我们假设字符集大小为常数。如果字符集大小不是常数,SAM 的时间复杂度就不是线性的。从一个结点出发的转移存储在支持快速查询和插入的平衡树(map)中。因此如果我们记$\sum$为字符集,$|\sum|$为字符集大小,则算法的渐进时间复杂度为$O(nlog|\sum|)$,空间复杂度为$O(n)$。然而如果字符集足够小,可以不写平衡树,以空间换时间将每个结点的转移存储为长度为$|\sum|$的数组(用于快速查询)和链表(用于快速遍历所有可用关键字)。这样算法的时间复杂度为$O(n)$,空间复杂度为$O(n|\sum|)$。
这两种转移方式我都实现了一遍,并且在SAM基础上解决了前面列举的问题,下面是具体实现的代码
平衡树(map)版本
展开代码
1 |
|
数组(array)版本
展开代码
1 |
|