后缀自动机(SAM)学习小记
来源:互联网 发布:闪讯网络电缆没有连接 编辑:程序博客网 时间:2024/05/17 22:11
Text
自动机的概念此处不解释。。
引入
我们需要一种数据结构能够识别一个字符串S的所有后缀
一种方法是直接建一棵Trie树,把每个后缀扔到里面去
这样的时空复杂度都是O(N^2)的,不能满足我们的要求
SAM应运而生
观察建好的Trie树,我们发现有很多的状态是冗余的,利用率低下
核心思想
SAM的思想就是将同一类的状态缩到一个点上
这样原来的Trie就变成了一个DAG
定义集合
对于Trie上某一个节点,它所代表的字符串是唯一的,是S的某一个子串。
对于某一个节点记录一个
那么只要有了Right集和len,我们就能获得这个字符串了
就是Right集中的位置向左len个长度
为了方便理解,设Right集合中的元素为
那么
我们尝试合并状态,尝试将Trie上所有Right集相同的点缩到一起
那么合并以后,一个节点所代表的字符串变成了多个,一个节点的len变成了一个区间,记为
这个节点所代表的字符串就是Right集中的位置向左[min,max]这个区间长度所得到的字符串集合
定义
设当前点为p
那么显然有性质,fail[p]所代表的字符串一定都是p所代表的字符串的后缀
并且
所以实际上我们并不需要记录min
画个图很容易发现这是正确的
可以发现fail指针构成了一棵树
合并后的东西就是构造出来的SAM了
SAM的性质
首先显而易见的,这个SAM不仅能识别S串所有的后缀,同时也能识别所有的子串,并且相同的子串不会重复出现
对SAM进行DFS,走过的边组成的字符串就是S的子串,每种走法唯一对应一个子串
其次,节点之间的Right集要么一个是另一个的真子集(在fail树上的祖先),要么就不相交
如果Right集合是相交的,那么一个串必定是另一个串的后缀,那么一定成真子集关系
第三,它的转移边数和节点数都是O(|S|)的
放到fail树上考虑
很明显,因为要么不相交,要么是真子集,那么最坏情况就是叶子节点的Right集只有一个元素,然后每增加一个节点就合并一些
显而易见最多只会有2|S|个节点
同时转移边数也是O(|S|)的
此处不给出证明,有兴趣者可以自行查找。。。
SAM的构造
现在的问题是如何在O(|S|)的复杂度内将这个SAM构造出来
考虑已经构造出了S的一个前缀S1,这个前缀结尾位置为
假设之前走到的最末的一个点为
我们需要对所有Right集合中有L这个位置的点进行修改,因为这些点可以走一条c的边进入我们新的状态。
Right集合有L这个位置,那就是last的fail树上到根的路径咯
新加一个点np
那么从last开始在fail指针上跑,如果跑到的点没有c的出边,那就加上,指向np(直到跑到根)
如果当前点(设为p)有一个c的出边了,指向q
那么是不是应该将np的fail指向q呢
不一定
举个例子
S串为AAAAcAAAc
p所代表的最长的串是AAA,即
分情况讨论
maxp+1=maxq ,也就是说q代表的最长的串是AAAc,q最多只能从p过来,没有比p过来更长的了,此时发现q的Right集真包含了np的Right集,并且显然Rightq 是最小的
那么failp=q maxp+1<maxq ,q代表的最长的串可能是AAAAc,发现它的Right集和np没半毛钱关系
此时可以新建节点nq,将q拆成两部分,一部分就是nq,maxnq=maxp+1 ,一部分就是剩下的q,max不变,minq=maxnq+1
实际意义就是将长度小于等于AAAc切出来给nq,把长度大于它的留给原来的q
nq最长代表AAAc,q最短代表AAAAc
那么显然failq=nq ,可以发现此时nq和第一条一样了,那么failnp=nq
同时nq的出边、fail全部复制q的,这也显而易见
然后可以发现现在的p已经不能走到q了,而是走到nq
那么从p开始,沿着p的fail链走,如果c的出边是q的改成nq,直到找到第一个不是的。(上面的肯定都不是了)或者已经到根
那么就构造完毕了
其他的复杂度显然,只需要考虑在fail上跳的复杂度
记住结论就好了,总复杂度仍然是O(N)的
此处不给出证明,有兴趣者可以自行查找其实是博主太弱不会势能分析。。。
模板的话,可以参考http://blog.csdn.net/hzj1054689699/article/details/78743488
广义SAM
就是可以多个字符串的SAM合并成一个
首先将这个这些字符串建成Trie,然后在Trie上BFS,按照这个的顺序向SAM里加,last相应的是Trie上的父亲
为啥不能DFS?好像是说势能分析的时候会有问题,会被卡成N^2
应用
因为SAM可以识别S的所有字串,所以。。。
最基础的就是求两个串的最长公共子串,这是O(N)的
直接将其中一个建好SAM,用另一个在上面跑,匹配失败就沿着fail跳,当前最长长度就是当前点的max
还可以在SAM上DP,fail树上DP什么的。。。
- 后缀自动机(SAM)学习小记
- 【后缀自动机sam学习小记】
- 后缀自动机(SAM)学习笔记
- 后缀自动机(SAM)学习指南
- 后缀自动机(SAM)模板
- 后缀自动机学习小记
- 后缀自动机学习小记
- 后缀自动机学习小记
- SAM后缀自动机学习小记 Poj 1509 Glass Beads (字符串最小表示)
- 【后缀自动机】【SAM】【自动机】【数据结构】后缀自动机理解(入门)
- SAM 后缀自动机——学习笔记
- 后缀自动机-SAM学习大记
- 后缀自动机(SAM)的一个DEMO
- [SAM]后缀自动机
- 后缀自动机SAM
- Sam后缀自动机模板
- 后缀自动机SAM
- 后缀自动机SAM
- Flex PopUpManager 弹出窗口居中
- PIM-DM/SM (2)(协议包的区别)
- js弹幕效果_js弹幕滚动_源代码_写法!
- SAS 中 PROC SQL过程步详解
- 微信和支付宝的被动扫码支付
- 后缀自动机(SAM)学习小记
- JS实现数值自动增加动画
- 用java.util.Properties类读取属性文件的内容,或者把属性写到xml文件中
- IE下的hack
- 3364-数据结构实验之图论八:欧拉回路
- 最详细的Android贪吃蛇,人人都学的会
- Linux下的rar和unrar命令的使用
- DrawerLayer+NavigationView 实现侧滑菜单
- OpenGL ES基础教程