后缀自动机学习资料

大部分摘抄,小部分原创。
http://blog.csdn.net/sprintfwater/article/details/11880573 (写错了)
http://blog.csdn.net/huyuncong/article/details/7583214#comments
http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html
膜大神,我就写不出这么清楚的资料。
不过还是总结一下吧,不然会忘。


一些不重要的话:第一次听说后缀自动机是傅老师说的。当时还是个弱的不行不行的蒟蒻(现在也是)。那时只听说过后缀数组,AC自动机都不会写- -||。就随便口胡一句:会后缀数组不够吗。她说:如果后缀数组够,要SAM干嘛。现在想想当时我真是naive啊。(2015前半年)
然后在那之后,学会了AC自动机。傅老师那句话一直记得,所以没学后缀数组,直接看了clj的2012冬令营的ppt和fhq的blog。看了好久没看懂。未果。开始怀疑人生了。然后弃了一段时间的坑,学了后缀数组(的模板)。当然后来想了想,他们是太神了,我太弱了,但并不代表我需要怀疑人生。clj写的真的太抽象了
然后SAM就耽误到了现在。有想法学实在某校内oj上刷模板题,有这道题,本来周一想学,学着学着困了。不过找到了好的讲解。今天正式学会了吧。
我看的第一个的图,第二个的讲解(第二个也有图,最开始没看见- -||)


在后缀自动机中,每个结点储存的信息有:
son[26]:返回该结点对应的子串加上某个字符后生成的合法子串在后缀自动机中所对应的位置(其实就和字母树一样),如果该指针不存在,就说明这样的子串是不存在的(即不是s的子串)
pre:注意这不是返回它的父结点(因为某个点有可能成为多个结点的儿子),而是返回上一个可以接收后缀的结点(如果当前结点可以接收新的后缀,那么pre指向的结点也一定可以接收后缀).
step:返回的是从根结点走到该结点,最多需要多少步.

后缀自动机的几个性质:
①从root到任意结点p的每条路径上的字符组成的字符串,都是当前串t的子串.
②因为满足性质一,所以如果当前结点p是可以接收新后缀的结点,那么从root到任意结点p的每条路径上的字符组成的字符串,都是必定是当前串t的后缀.
③如果结点p可以接收新的后缀,那么p的pre指向的结点也可以接收后缀,反过来就不行.
下面的叙述中,将直接应用这两个性质.

节点分为可接受状态节点和非可接受状态节点。可接受状态就是说根节点到该节点组成了上一状态的后缀,即它在添加你现在要add的字符,它还是后缀。

添加字符x:
np:新加入的节点编号。
p:上一个新增节点按照pre走的节点。
q:p的x儿子。

当前建立的后缀自动机是对应字符串t的,现在要插入字符x,把t的后缀自动机变成tx的后缀自动机.
我们的做法是:
假设当前跳到p结点,如果p没有x儿子,那么它一定可以接收新来的字符,然后就把p的x儿子赋值为np.
然后,就要处理有x儿子的结点了,假设p的x儿子是q.只有2种情况:
①step[q]=step[p]+1.
因为我们要后缀自动机的结点尽量少,所以要尽量共用一些信息.这是对应的图:
这时,p点是满足性质②的.这时,如果可以把np直接接到p后面,就可以省下很多空间了,但是因为q点的存在, np不能直接接到p后面,否则p-q的信息就丢失了.那么能不能把q当成np呢?就是说q可不可以像np那样,作为t的”最后一个字符”,来接收新的后缀呢?答案是肯定的.但p可以接收新的后缀,q就不一定能接收新的后缀,这样做会不会有问题?
后缀自动机学习资料_第1张图片
本来,这样的做法是不行的(这是情况②要解决的问题),但step[q]=step[p]+1,保证了:q原本是从p的路径上来的,而且p和q之间不会夹杂其它字符.虽然q本来不一定可以接收新的后缀,但p可以接收后缀x,如果当前经过p来到q,就可以视为是在t的某个后缀后面插入了x(现在q就是那个x),并且在下一次插入的时候,q也可以接收后缀(因为它现在可以被视为x的结点了),所以就把np的pre指向q.
后缀自动机学习资料_第2张图片
②step[q]>step[p]+1
这和上一种情况一样,也面临着q点是否可以当成x结点的问题.在上一种情况的描述中,我们可以知道, step[q]=step[p]+1可以保证q原本是从p的路径上来的,而且p和q之间不会夹杂其它字符,所以可以直接把q结点当成x结点.那么反过来, step[q]>step[p]+1,就说明p和q之间有可能会夹杂其它字符,这就不能保证把q当成x结点以后,到q的路径都是tx的后缀了,于是我们不能采取和前一种情况一样的做法.但是,我们可以模仿前一种情况的做法.
上面的做法合法,是因为step[q]=step[p]+1,那么如果新建一个结点nq来代替q,同时保证step[nq]=step[p]+1就相当于第一种情况了,这时,只要把q的son边和pre边都copy到nq上即可.但是别忘了把nq的pre改为p,再把q和np的pre都改为nq.
因为现在nq代替了q,所以np的pre是nq.由性质③可知nq的pre只能是p.同样的,q和nq也满足性质③,所以q的pre只能是nq.
最后,还要再按p的pre指针往上跳,把son[x]=q的p结点改为son[x]=nq(因为nq代替了q).
后缀自动机学习资料_第3张图片

后缀自动机学习资料_第4张图片

后缀自动机学习资料_第5张图片

你可能感兴趣的:(后缀自动机)