后缀自动机(SAM)

OI WIKI进行了抄写删减

定义

字符串 s 的 SAM 是一个接受 s 的所有后缀的最小 DFA(确定性有限自动机或确定性有限状态自动机)。

  • SAM是一张有向无环图。节点称作状态,边称作转移

  • 图存在一个源点t0,称作初始状态(即下图红点),其他节点均可从t0出发到达

  • 转移依赖字符进行

  • 存在一个或多个终止状态(下图绿点)

  • 在满足以上的同时节点数最少

可看作对字符串所有后缀建Trie树,然后对相同的状态(即下文endpos集合相同)缩点

以aaba为例

以abbb为例

线性构造

先明确一些概念

结束位置endpos

字符串s的任意非空子串t,记endpos(t)为t在s中的所有结束位置。如abcbc,endpos(bc)=3,5。
两个子串endpos集合可能相等:endpos(t1)=endpos(t2)。于是将所有子串按照endpos集合分为若干等价类。

SAM中每个状态对应一个或多个endpos相同的子串。加上初始状态,SAM的状态个数等于endpos相同的一个或多个子串组成的集合个数+1。

lemma1

两个非空子串 u 和 w(假设 ∣u∣≤∣w∣)的 endpos 相同,当且仅当字符串 u 是 w 的后缀。

lemma2

考虑两个非空子串 uw (假设 |u||w| )。那么要么 endpos(u)endpos(w)= ,要么 endpos(w)endpos(u) ,取决于 u 是否为 w 的一个后缀:
{endpos(w)endpos(u)if u is a suffix of wendpos(w)endpos(u)=otherwise

lemma3

将一个endpos等价类中所有子串按长度递增排序,长度形成连续段

对于一个状态p,link指向最近的一个q,endpos(p)endpos(q)

以abcbc为例,link构成一棵树,父亲是儿子的最大后缀

最大长度len

对于一个状态p,其表示的所有子串中最大长度为len,最小长度为minlen

考虑一个子串,其endpos与p有交且长度在minlen到len之间,则这个子串包含在状态p中,印证lemma3

在考虑一个子串,其endpos与p有交且长度小于minlen,则这个子串是p在link上的祖先。于是得到minlen[p]=len[link[p]]+1,所以不需要记录minlen。

在link树上,从根到叶子的一支,其子串的长度是连续的,且上为下的后缀

到现在你可以发现,后缀自动机中的后缀只存于link关系中,而节点存的是子串

过程

一开始只包含一个状态t0,编号为0,len=0,link=-1

现加入一个字符c

创建新状态cur,lst为加入上一个的状态,首先就有len[cur]=len[lst]+1,即全串。

然后从lst开始向上跳link,对其添加字符c,即对当前串的所有后缀添加字符c。若没有c的转移,就一路添加到t0,这个字符从没出现过,link=0。

假设现在我们找到了一个状态p,其可以通过字符 c 转移到状态q,停下。此时p上面的所有状态都有c的转移。

记向 SAM 中插入当前字符 c 之前的字符串为 s

转移 (p,q)意味着我们尝试向自动机内添加一个 已经存在的 字符串 x+c (其中 xs 的一个后缀,且字符串 x+c 已经作为 s 的一个子串出现过了)。我们要把后缀链接连到一个状态上,且其中最长的一个字符串恰好是 x+c ,即这个状态的 len 应该是 len(p)+1 。考虑如果不是,即len(q)>len(p)+1,即最长字符串是ax+c,但ax不是s的后缀,即ax+c不是cur的后缀,那么当前link不合法。这种情况下,我们必须通过拆开状态 q 来创建一个这样的状态。

仍以abcbc为例,此时向abcb加入c

我们复制状态 q ,产生一个状态 clone ,将 len(clone) 赋值为 len(p)+1 ,将 q 的所有转移复制到 clone。我们也将从 clone 出发的后缀链接设置为 q 的后缀链接的目标,并设置 q 的后缀链接为 clone

将从 cur 出发的后缀链接设置为 clone
最后一步我们将一些到 q 转移重定向到 clone 。我们需要修改哪些转移呢?只重定向相当于所有字符串 w+c (其中 wp 的最长字符串)的后缀就够了。即沿着后缀链接遍历,从结点 p 直到虚拟状态 1

代码

证明

状态数

转移数

操作数(算法复杂度)

posted @   yisiwunian  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
点击右上角即可分享
微信分享提示