- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
前言
勤劳的hgz又来更新博客了。
先说点废话,WC结束了,蒟蒻hgz铜牌滚粗,也没什么好写的,就来写下刚弄懂的SAM。这玩意我感觉非常神奇又比较难懂(可定是我学的太少了),所以就码码字放松下。
定义
自动机:对于一个给定的属于该自动机的状态和一个属于该自动机字母表的字符,它都能根据事先给定的转移函数转移到下一个状态。能看到这篇文章的dalao们应该都会AC自动机,回文自动机,等等我听不懂的算法吧,那应该对自动机有一个自己的了解,我就不多说了。那么SAM是一个DFA,它接受且只接受字符串S的后缀。
Endpos:对于S的一个子串s,endpos(s)=s在S中的所有出现的结束位置集合。比如对于S=”hekaitaijule”,有endpos(“ai”)={5,8}
那么SAM干了什么事呢,我们可以发现,对于这个字符串的一些结束位置相同的子串,他们的出现位置集合endpos是相同的,比如endpos(“tai”)=endpos(“itai”)=endpos(“aitai”)=endpos(“kaitai”)={8},这些后缀的长度连续。所以可以把这些endpos一样的状态合并起来,同时给这个状态两个变量maxlen和slink。
Maxlen表示这个状态能接受的最长后缀长度,slink是后缀连接。
举个例子,对于上面的字符串,在自动机上走i与ai后到达的状态sta现在属于同一个状态,而更长一点的后缀tai走到的状态sta2就不一样了,它总共也就出现了一次,所以maxlen[sta]=2,而对于一个前缀的所有后缀,随着长度变小,出现次数可能增加,就会有新的节点产生,这时就要维护slink,在这个例子中slink[sta2]=sta。
这里给出一张hihocoder上的对S=aabbabd建立的后缀自动机的图和表格,虚线边即为slink,来检查一下对slink的理解是否有偏差。
强调一下,SAM一个节点代表的字符串是一个前缀的一部分连续长度的后缀,而slink是对把一个前缀的所有后缀的所有状态节点串起来,沿slink走的时候,是走向了更短的后缀。
再给出一个你可能一眼看出来的性质。
s1是s2的后缀当且仅当endpos(s1) ? endpos(s2)。
因为s2包含了s1,所以s2出现的地方s1都出现了,而s1还可能在更多地方出现。
于是沿着slink数组,我们就可以构出一棵树,我们把它叫做parent树。
可以发现,树上的父亲与孩子在字符串上是前后缀关系,在endpos上是取并集的关系。
构造
如果看到这里没有疑问的话,那您可真是大佬,就接着往下看吧,否则回去对照表格图示和定义再理解一下咯。其实前面都还好,之前掉到clj论文的一些证明的坑里去了,一下没想明白,其实下面才是最坑的。
建立SAM,有一个时空复杂度均为O(n)的算法(虽然我不会证),而且是在线的增量构造。先介绍下对于每个状态sta我们记录什么。
Maxlen:sta能代表的最长的字串长度(或者说能走到sta的最长的子串长度)
A[sta][]:sta的转移函数
Fa:其实是slink
注意在实际建立的时候,我们并不显式的把endpos集合构造出来。
假设我们已经构造好了S(len=n)的SAM,现在我们要在尾部添加一个字母c,那么我们要改变一下这个SAM使得其能识别S[n]+c S[n-1..n]+c .. S[1..n]+c等后缀。
那么怎么做呢?
首先想到一点,我们令能代表S[n]的节点为last,那么沿着last的fa指针在parent树上跳到rt为止,所有经过的节点能代表的字符串的并就是S[n]的所有后缀,这个过程形成的连表示为suffix-path(last-S),称suffix-path(last-S)这条链为主链。而且肯定要至少新建一个节点,因为S+c这个字符串的endpos肯定不和前面的节点相同。
先考虑一个最简单的情况,suffix-path(last-S)上的所有状态都没有c这条转移边,那么我们只需要添加一个新节点np,用上面那个方法遍历这条链上的所有节点exist_p,增加 a[exist_p][c]=np即可,再把fa[np]设为root,因为所有新增后缀并没有在不同节点中。
当然大多数情况下都不是这样,如果在做这个我们碰到了一个节点p,它的a[p][c]并不是空的,这个指针现在指向节点q。这里分两种情况
maxlen(q)=maxlen(p)+1,明确一点,在主链上的节点p的maxlen(p)代表的字符串s一定是S的一个后缀,这很显然,所以呢,当满足前面这个条件时,我们就知道,其实从s开始及更短的后缀(在suffix-path(p-S)链上)加上字母c后的那些串,其实在suffix-path(q-S)链上,这样反而省事了,我们找到了剩下要添加
原创力文档


文档评论(0)