Suffix automaton 后缀自动机小记
本文意图从 sam 的性质解释 sam 的构建原理,使得之后复习时对 sam 的特点有更清晰的理解.
注:文章受 Alew_Wei 的博文 常见字符串算法 II:自动机相关 启发.会有许多相关的应用,感谢.
记号/约定:
- T T T:sam 的起点,代表空串的等价类.
- t p t_p tp:从 T T T 转移截止到状态 p p p 的一个子串.
- c p , q c_{p, q} cp,q:状态 p p p 转移到状态 q q q 的字符.
- δ ( p , c ) \delta(p, c) δ(p,c):状态 p p p 经过 c c c 转移到的状态.
- e n d p o s ( t ) endpos(t) endpos(t):字符串 t t t 结束位置的集合.
- s u b s t r ( p ) substr(p) substr(p):状态 p p p 代表的子串集合.
- s h o r t e s t ( p ) shortest(p) shortest(p):状态 p p p 代表的最短子串.
- l o n g e s t ( p ) longest(p) longest(p):状态 p p p 代表的最长子串.
- m i n l e n ( p ) minlen(p) minlen(p): ∣ s h o r t e s t ( p ) ∣ |shortest(p)| ∣shortest(p)∣.
- l e n ( p ) len(p) len(p): ∣ l o n g e s t ( p ) ∣ |longest(p)| ∣longest(p)∣.
- l i n k ( p ) link(p) link(p):状态 p p p 的后缀链接.
一.引理
4 个引理是重要而容易理解的.
- 两子串的 e n d p o s endpos endpos 包含或不交.
- 对于一个状态 p p p, s u b s t r ( p ) substr(p) substr(p) 中的子串连续,并且较短的串是较长的串的后缀.
- 后缀链接构成一棵根节点为 T T T 的树.
- 后缀链接构成的树和由 e n d p o s endpos endpos 包含关系构成的树相同.
对于后缀链接的理解:状态 p p p 的后缀链接为 q q q,即从 l o n g e s t ( p ) longest(p) longest(p) 开始不断丢弃子串前端的字符,直到 s h o r t e s t ( p ) shortest(p) shortest(p) 为止,子串 e n d p o s endpos endpos 没有改变.继续丢弃前端的字符,子串的 e n d p o s endpos endpos 会新增加一些位置,变成另一个状态,即 q q q.
二.性质/结论
有 sam 的结构结合引理可以得到这些性质.这些性质是很重要的.
- 关于后缀链接
- 从状态 p p p 沿后缀链接到 T T T,所有状态 q q q 的区间 [ m i n l e n ( q ) , l e n ( q ) ] [minlen(q), len(q)] [minlen(q),len(q)] 不交,其并构成区间 [ 0 , l e n ( p ) ] [0, len(p)] [0,len(p)].
- 从状态 p p p 沿后缀链接到 T T T,所有状态 q q q 的 s u b s t r ( q ) substr(q) substr(q) 的并集构成 l o n g e s t ( p ) longest(p) longest(p) 的所有后缀.
- 关于转移
- 若存在转移 p → q p \rightarrow q p→q, ∀ t p ∈ s u b s t r ( p ) , t p + c p , q ∈ s u b s t r ( q ) \forall t_p\in substr(p), t_p+c_{p, q}\in substr(q) ∀tp∈substr(p),tp+cp,q∈substr(q).
- ∀ t q ∈ s u b s t r ( q ) , ∃ t p ( p → q ) , t p + c p , q = t q \forall t_q \in substr(q), \exists t_p(p\rightarrow q),t_p+c_{p,q}=t_q ∀tq∈substr(q),∃tp(p→q),tp+cp,q=tq.
- 还是转移
- 对于状态 q q q,不存在 p → q , l e n ( p ) + 1 > l e n ( q ) p \rightarrow q,len(p)+1 > len(q) p→q,len(p)+1>len(q).
- 对于状态 q q q,唯一存在 p → q , l e n ( p ) + 1 = l e n ( q ) p \rightarrow q,len(p)+1=len(q) p→q,len(p)+1=len(q).
- 对于状态 q q q,唯一存在 p → q , m i n l e n ( p ) + 1 = m i n l e n ( q ) p \rightarrow q,minlen(p)+1=minlen(q) p→q,minlen(p)+1=minlen(q).
到这里,我们回头考察一下这些性质.1 中的性质可以通过 引理 中 对于后缀链接的理解 证明.2 中的性质可以用 sam 的 D A W G DAWG DAWG 的性质证明.3 中的性质则是 1 和 2 的结合和补充.
记 m x t r s ( q ) = p ( p → q , l e n ( p ) + 1 = l e n ( q ) ) , m n t r s ( q ) = p ( p → q , m i n l e n ( p ) + 1 = m i n l e n ( q ) ) mxtrs(q)=p\ (p \rightarrow q,len(p)+1=len(q)),\ mntrs(q)=p\ (p \rightarrow q,minlen(p)+1=minlen(q)) mxtrs(q)=p (p→q,len(p)+1=len(q)), mntrs(q)=p (p→q,minlen(p)+1=minlen(q)).
- 对于状态 q q q,所有 p ( p → q ) p\ (p \rightarrow q) p (p→q) 在 parent tree 上形成一段从 m x t r s ( q ) mxtrs(q) mxtrs(q) 到 m n t r s ( q ) mntrs(q) mntrs(q) 深度由深到浅的链.
结论 4 结合前面的结论是容易理解的.
从图上,我们可以这样去理解它:
三.构建
有了 一、二 两部分的铺垫,构造的过程就比较易懂了.考虑新增一个字符 c c c 构成的串为 s s s,之前的串为 s ′ s' s′. s ′ + c = s s'+c=s s′+c=s.令 ∣ s ∣ = n |s|=n ∣s∣=n.
相较于 s ′ s' s′, s s s 中只多出了一个新子串 s s s,只有 s s s 的后缀 e n d p o s endpos endpos 新增了 n n n.
在 parent tree 上,我们记一个状态 p p p 到 T T T 的简单路径经过的状态集合为 R d p Rd_p Rdp.
新建节点
n
p
np
np,
e
n
d
p
o
s
(
n
p
)
=
n
endpos(np)=n
endpos(np)=n.
s
s
s 的真后缀可以表达为
s
′
s'
s′ 的后缀
+
c
+c
+c.设状态
p
s
′
p_{s'}
ps′ 满足
s
′
∈
p
s
′
s' \in p_{s'}
s′∈ps′,$向上遍历
R
d
p
s
′
Rd_{p_{s'}}
Rdps′,在这个过程中处理
p
→
n
p
p \rightarrow np
p→np 的新增转移并找到
l
i
n
k
(
n
p
)
link(np)
link(np).
对于过程中第一个
p
∈
R
d
p
s
′
,
∃
δ
(
p
,
c
)
p\in Rd_{p_{s'}}, \exists\delta(p, c)
p∈Rdps′,∃δ(p,c),每个之前的节点
p
′
p'
p′ 有新增转移
δ
(
p
,
c
)
=
n
p
\delta (p, c)=np
δ(p,c)=np.
在这部分中,
∀
t
p
′
\forall t_{p'}
∀tp′,
t
p
′
+
c
t_{p'}+c
tp′+c 不属于
s
′
s'
s′ 中的任意一种等价类.故
t
p
′
+
c
∈
n
p
t_{p'}+c \in np
tp′+c∈np.
记 δ ( p , c ) = q \delta(p, c)=q δ(p,c)=q.接下来我们分两种情况讨论:
- l e n ( q ) = l e n ( p ) + 1 len(q)=len(p)+1 len(q)=len(p)+1.这说明 ∀ t q \forall t_q ∀tq, t q t_q tq 为 s s s 的后缀.可以直接让 l i n k ( n p ) = q link(np)=q link(np)=q.
-
l
e
n
(
q
)
>
l
e
n
(
q
)
+
1
len(q)>len(q)+1
len(q)>len(q)+1.这说明
∃
t
q
\exists t_q
∃tq,
t
q
t_q
tq 不是
s
s
s 的后缀.我们把
q
q
q 分为两部分
n
q
,
m
q
nq,mq
nq,mq 分别表示是
s
s
s 后缀的部分和不是
s
s
s 后缀的部分并用两者代替
q
q
q.令
l
i
n
k
(
n
q
)
=
l
i
n
k
(
q
)
,
l
i
n
k
(
m
q
)
=
n
q
,
l
e
n
(
n
q
)
=
l
e
n
(
p
)
+
1
,
l
e
n
(
m
q
)
=
l
e
n
(
q
)
link(nq)=link(q),link(mq)=nq,\ len(nq)=len(p)+1,len(mq)=len(q)
link(nq)=link(q),link(mq)=nq, len(nq)=len(p)+1,len(mq)=len(q).它们的转移都和
q
q
q 的转移相同.继续跳
p
p
p parent tree 上的祖先
p
′
p'
p′,
δ
(
p
′
,
c
)
\delta(p', c)
δ(p′,c) 能够表达的子串一定 全部 为
s
s
s 的后缀,故不用继续向上检查.直接令
l
i
n
k
(
n
p
)
=
n
q
link(np)=nq
link(np)=nq.
这之后,我们顺着 p p p 向上跳后缀链接,将满足 δ ( p ′ , c ) = q \delta(p', c)=q δ(p′,c)=q 的点进行操作 δ ( p ′ , c ) ← n q \delta(p', c) \leftarrow nq δ(p′,c)←nq.
发现我们在上述讨论中完美地构造了状态 n p np np.构造它的过程中巧妙地串联起来 s ′ s' s′ 和 s s s 后缀的关系.
关于增量法构造 sam 的上述讨论,都是和之前所提到的结论相照应的.
在理解时,尤其注意结合 性质 4:对于状态
q
q
q,所有
p
(
p
→
q
)
p\ (p \rightarrow q)
p (p→q) 在 parent tree 上形成一段从
m
x
t
r
s
(
q
)
mxtrs(q)
mxtrs(q) 到
m
n
t
r
s
(
q
)
mntrs(q)
mntrs(q) 深度由深到浅的链.
四.应用、例题
这部分可能会在以后更新.