首页 > 代码库 > 后缀自动机的直观理解
后缀自动机的直观理解
后缀自动机(SAM)
搜了网上,多介绍应用,[3]算是一个比严格的定义性描述,并给出了证明。但是这个证明我并未看懂,下面综合一些资料给一些个人的直观但不失严谨的理解。
给定一个串A的后缀自动机是一个有限状态自动机(DFA),它能够且仅能够接受A的后缀,并且我们要求它的状态数最少。
设n=|A|, 状态数:st=[n+1,2n-1], 边数:eg=[n,3n-4]。构造:空间复杂度:26*st, 时间复杂度O(3n)。查询:O(|q|);
可以看出,我们有可能把26*st优化到3*st的。
先上图,有个直观认识:
<fig1>
这是表示串A="abaaaba"的后缀自动机,红色的S表示开始状态,红色的表示接受状态,黑色的表示非接受状态。从这个图可以看出,某个节点可以是多个节点的儿子,节省了状态空间。
定义:
状态p :=R(u)的等价类。其中R(u) := {u在A中出现位置右端点}。
比如上图中状态7识别两个后缀,满足R("aba") = R("ba")={3,7}。p称为接受状态是指自动机识别了一个从初始状态到p所表示的子串是A的后缀。
状态转移(p,c,q)表示状态p通过字符c转移到状态q。
后缀函数S(A,u):= u的最长后缀v,满足v不在u等价类中。
u=A时称为后缀链接,[3]引理1.5说S(A,A)=A中至少出现两次的最长后缀。
记最后一个加入的状态为last,则last,S(A,last), S(A,S(A,last),...组成接受状态构成的后缀路径SP。注意的是其他非接受状态的后缀链接也可以指向某个接受状态。 后缀链接指向上一个可以接受后缀的结点
长度函数L(A,p):= 初始状态到p的最长路径长度。即从根节点走到该节点,最多需要多少步。
下面我们考察状态机A增加一个字符x后,A的状态变化。
令z是A出现的且是Ax的最长后缀, zp是A中最长子串且zp,z属于A的同一等价类。
推论2.3.12说,如果x不在A中,则A的等价类在Ax中不变。(I)
推论2.3.11说,如果z=zp, 则A的等价类在Ax中不变。(II)
定理2.3.10说,如果z!=zp,则A中与z的等价类在Ax要改成zp。(III)
例子, 如下图,A="ccccbbccc", x=‘d‘对应(I),S(Ax,Ax)="";
后缀链接没有必要显示画出来,因为观察SP,就知道是9->3->2->1->0。
x=‘c‘对应(II),z="cccc", R(z)={4}, zp=z, S(A,A)="ccc", S(Ax,Ax)=z;
x=‘b‘对应(III),z="cccb",R(z)={5}=R(zp),zp="ccccb", S(Ax,Ax)=z。
<fig2>
增量构造法:
设当前串为A,加入字符为x。
令p为R(A)={L(A)}对应的状态, 新节点np为R(Ax)={L(A)+1}对应的状态。
np显然应该是Ax的一个接受状态,np应该挂接到哪个位置呢?
为了节省状态空间,我们应该尽可能公用公共前缀,且尽可能让图宽以降低路径长度。
因此从last开始,沿着后缀链接跳,直到跳到第一个有x出边的v节点。
对p所有没有x出边的后缀链接v=S(A,p), trans(v,x)=np, 找第一个有x出边的v,令q=trans(v,x),
1. 如果L(q) = L(p)+1, p-->q只有由x可达,我们只需把q作为接受状态,到q的路径都是Ax的后缀。
2. 如果L(q)!=L(p)+1, p-->q就可能有其他若干字符可达,虚拟一个节点nq表示1的情形,把q,np的S都指向nq。
核心代码只有20行(估计后缀树代码量要大很多,这也是SAM的优势之一):
void add(int x) { State p = last, np = new State(); np.val = last.val + 1; for(; (p != null) && (p.go[x] == null); p = p.fa) p.go[x] = np; if(null == p){ np.fa = root; }else{ State q = p.go[x]; if(q.val == p.val + 1){ np.fa = q; /*S(np)=q*/ }else{ State nq = new State(); nq.copy(q); /*trans(nq,*)=trans(q,*)*/ nq.val = p.val + 1; q.fa = np.fa = nq; for(; (p != null) && (p.go[x] == q); p = p.fa) p.go[x] = nq; } } last = np; }
Todo
我发现后缀链接很像KMP的向后跳。整理代码用模式串构造SAM,下周整理出来。
Ref
[1] 加速2,3 https://www.cs.duke.edu/courses/fall12/compsci260/resources/suffix.trees.in.detail.pdf
[2]后缀指针构造
http://marknelson.us/1996/08/01/suffix-trees
[3] Algebraic Combinatorics On Words.pdf
http://www.ctzsm.com/%E5%90%8E%E7%BC%80%E8%87%AA%E5%8A%A8%E6%9C%BA%E6%8A%A5%E5%91%8A/