字符串 (S) 的后缀自动机(SAM)是可以接受 (S) 的所有后缀的 DFA, 其状态数最少(最简状态自动机)。
串 (S) 的 SAM 的状态数与转移数都是 (O(|S|)) 的。
符号与表达约定
1. 对于 (S = "wowaka"), (S[1] = 'w'), (S[2] = 'o'), 意即下标从一开始。
2. 用 (SAM_S( ext{“string"})) 表示 (S) 的 SAM 的 (delta(start, ext{“string")}) , 意即 (“string") 终止于 (SAM_S( ext{“string"}))。
3. 分别用 (Pre_S、Suf_S、Sub_S) 表示字符串 (S) 的 所有前缀组成的集合、所有后缀组成的集合、所有子串组成的集合。
状态
显然地, 对于 (subs in Sub_S), (SAM_S(subs)
eq NULL), 然而 (S) 的子串数是 (O(|S|^2)) 的, 这说明对于不同的 (subs in Sub_S), (SAM_S(subs)) 可能相同。
实际上, 对于 (SAM_S) 的每个状态, 都有一个唯一的 (S) 的 endpos等价类, 使得里面的所有字符串都终止于这个状态。
endpos集合
设 (T) 为一个非空字符串, 则 (endpos^S(T) = {r | exists 1 le l le r, S[ldots r] = T})。
特别地, (endpos^S(NULL) = {0, 1, cdots, |S|})。[1]
endpos等价类
一个 endpos等价类 就是 (endpos^S) 相同的若干 (S) 的子串。
(SAM_S) 中包含了 (S) 的所有 endpos等价类。
对于一个状态 (v), 用 (endpos^S(v)) 表示终止于 (v) 的 endpos等价类, 用 (maxlen(v)) 表示 (max{ |T| ; ig| ; endpos^S(T) = endpos^S(v) }), (minlen(v)) 类似。
性质 1
任取 (SAM_S) 的两个不同状态 (v_1, v_2), 则以下三式有且仅有一个成立:
(1) (endpos^S(v_1) cap endpos^S(v_1) = varnothing)
(2) (endpos^S(v_1) subset endpos^S(v_2))
(3) (endpos^S(v_2) subset endpos^S(v_1))
(Proof.)
显然啊, 看下 (endpos^S(v_1) cap endpos^S(v_1)
eq varnothing) 的情况就行了。
性质 2
对于 (SAM_S) 的状态 (v), 所有满足 (endpos^S(T) = endpos^S(v)) 的字符串 (T) 的长度会取到 ([minlen(v), maxlen(v)]) 里的所有整数。
(Proof.)
显然, 用 (A subseteq S, ; S subseteq A ; ; Rightarrow ; ; A = S) 证就行。
转移
对于状态 (v), 其所有出边上的字符 (c) 一定是 (S[r+1], r in endpos^S(v))(如果存在的话) , 其所有后继状态 (nxt) 的 (endpos^S(nxt)) 互不相交。
状态的树形结构
对于两个状态 (v_1, v_2 in SAM_S), 称 (v_1) 为 (v_2) 的 parent 状态当且仅当 (endpos^S(v_2) subset endpos^S(v_1)) 且 (|endpos^S(v_1)|) 最小。[2]
任何状态(除了起始状态)的 parent 状态存在且唯一。
(Proof.)
存在性显然。(有 (endpos^S(NULL)))
唯一性嘛, 先假设有两个最小的, 由于都真包含一个状态, 所以交起来非空, 然而大小相等, 不可能有真包含的关系, 结合 状态 的性质1, 推出矛盾。
若状态 (v) 的 parent 状态为 (v_1), 则 (maxlen(v_1) + 1 = minlen(v))
(Proof.)
由于 (endpos^S(v) subset endpos^S(v_1)), 所以 (maxlen(v_1) in [minlen(v)-1, 0]), 然而 (|endpos^S(v_1)|) 是最小的, 所以 (maxlen(v_1) = minlen(v)-1)。[3]
状态数
(SAM_S) 的状态数是 (O(|S|)) 的, 具体地, 不超过 (2|S| + 1) 。
(Proof.)
在 parent 树中, 设 (f(n)) 表示 (|endpos_S| = n) 的状态的最大子树大小, 显而易见地, (f(n) ge 1 + f(x_1) + cdots + f(x_k) ; ; ; (x_1 + cdots + x_k = n, ; k ge 2))。
然而这并没有什么卵用, 现在用数学归纳法证明 (f(n) = 2n - 1):
1. (n=1, f(n) = 1), 成立。
2. (n ge 2), 相当于根节点 (|endpos^S| = n-1) 的情况下子树根的 (endpos^S) 里多了一个元素, 这个元素要么在某路径分叉, 使得整棵树多了一个节点, 要么直到叶子结点, 分两个叉, 使得整棵树多了两个节点, 此时 (f(n) = f(n-1) + 2 = [2(n-1)-1] + 2 = 2n-1)。
转移数
(SAM_S) 的转移数是 (O(|S|)) 的, 具体地, 不超过 (3|S|)
(Proof.)
首先, 以起始节点为根节点求出 (SAM_S) 的一颗外向树, 结合状态数上界可知树边数不超过 (2|S|)。
把 (S) 的每个后缀 (sf) 扔到 (SAM_S) 上转移, 对于经过的第一条非树边, 让 (sf) 与其对应, 每个 (sf) 最多对应一条非树边, 这就表明能被后缀对应的非树边最多有 (|S|) 条。
显然地, 每个非树边都是某个后缀的对应边(总是可以由起始状态通过树边到达非树边的发起状态), 结合上面的结论, 可知非树边最多有 (|S|) 条。
线性构造
采用增量法构造, 即 (SAM_{alpha eta zeta delta} ; ; stackrel{某种nb方法}{Rightarrow} ; ; SAM_{alpha eta zeta delta Delta})。