SAM(后缀自动机)速通

1|0约定

Σ 为字符集,|Σ| 为字符集大小。

2|0定义 & 定理

SAM 是一个接受 s 所有后缀的最小 DFA

定义 endpos(t) 表示字符串 ts 所有的结束位置(从 0 开始标号),方便起见,有 endpos(t0) 定义为 {1,0,,|S|1}
我们将所有 endpos 相等的字符串划分至同一个等价类

引理 1: 若字符串 s 的两个子串 u,v(|u||v|)endpos 相同,当且仅当 uv 的后缀;

引理 2: 对于字符串 s 的两个子串 u,v(|u||v|),满足

{endpos(v)endpos(u)if u is a suffix of vendpos(v)endpos(u)=otherwise

引理 3: 一个状态的字符串的长度恰好唯一覆盖 [minlen(u),len(u)],且长度短的字符串为长度长的字符串的后缀。

显然,SAMt0 和每个等价类对应状态构成。

我们令后缀链接 link(u) 链接至最长的 endpos 不同的后缀所对应的等价类。

引理 4: 所有的后缀链接构成一颗以t0 为根的树(即为后缀树)。

引理 5: 对于 t0 以外的状态 v,有 minlen(v)=len(link(v))+1

引理 6: 任意状态 v0 顺着 link 遍历,总会到达 t0。路径中我们可以得到互不相交的区间序列 [minlen(vi),len(vi)],且并集为 [0,len(v0)]

3|0算法

该算法为在线算法,且为保证空间复杂度,我们只保存 lenlink 的值,而非 endpos
初始 SAM 只包含一个状态 t0,编号为 0,并指定其 len=0,link=11 为虚拟状态)。

3|1流程

  • last 为添加字符 c 前,整个字符串对应的状态(初始 last=0)。
  • 创建新状态 cur,令 len(cur)=len(last)+1
  • 从状态 last 开始,不停向后缀链接遍历直至其存在到字符 c 的转移或已到达虚拟结点 1,记该状态为 p。将遍历中的状态(除了 p)向 cur 添加转移。
  • p=1,令 link(cur)=0 并退出。
  • p 通过 c 转移得到的状态为 q,分两种情况讨论:
    • len(p)+1=len(q),令 link(cur)=q 并退出;
    • 否则,我们创建新状态 clone,并令其复制 q 的状态,再令 len(clone)=len(p)+1,link(cur)=link(q)=clone。最终我们通过后缀链接将 p 往回走,只要存在 pq,就将转移重定向至 clone
  • 以上三种情况,在退出后令 last=cur

3|2证明

1|0正确性证明

这是速通,有什么证明。

1|0复杂度证明

复杂度线性,不予证明。

1|0状态数证明

对于一个长度为 n 的字符串,状态数不超过 2n1(n2)。易证。

1|0转移数证明

对于一个长度为 n 的字符串,转移数不超过 4n3(n3)。不予证明。


__EOF__

本文作者TrueFalse
本文链接https://www.cnblogs.com/cqbzljh/p/18699459.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cqbzljh  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示