如何手搓一个 SAM

注意!该博客只讲做法!
据某位高人所言,这位高人手搓 SAM 手搓了一个月,最终熟练使用了 SAM,得道后飞升为字符串之仙。
先看代码:
1 | char s[N]; |
那么讲步骤:
- SAM 包含一个 DAG 和一棵 Fail 树。每一个节点维护其在 DAG 上的出边、
和 。 为 代表的节点, 为新节点,即 代表的节点。 为存在 的第一个节点的 ,这个点本来是预定成为 的 。 为当 成为不了 的 时,拆出来的一个点,这个点才能成为 的 。 - 新建节点
,定其 为上一个节点 的 。 - 将
沿着 Fail 树跳,将所有没有 的点的 设为 。直到跳出根或是 存在就停止。 - 若
跳出根了,即 ,则设 。退出。 - 否则,存在
。令其为 。 - 若
,则设 。退出。 - 否则克隆节点。新建节点
,定其 。 - 然后将
的 转移至 ,再定 , 。 - 然后再跳
,将 设为 ,直到 跳出根或是 就停止。 - 最后复制
的 DAG 出边信息至 。退出。
下面举几个例子(Fail 边用蓝色表示, 在右下角标注):
い・ababc
. 情况 1、2
建出
建出
现在
遇到没有
然后因为最后跳出了根,所以
现在
但是注意!这里因为
定
首先还是跳树建边,直到发现存在
然后看
这里
ろ・aabab
. 情况 3
首先还是,插入 aa
。
然后插入 b
,跳树建边,最后连 fail。
然后插入 a
,因为存在
现在插入 b
,然后存在
答案是否定的。我们应该拆
那么首先,新建一个节点
然后,修改
fail[nq] = fail[q]
,将的 修改为 ,即 。 fail[q] = nq
,将的 修改为 ,即 。 fail[np] = nq
,将的 修改为 。
然后,跳
,那么修改 ,跳链修改 。 ,那么修改 ,跳链修改 。 - 跳出根外,结束。
注意一点:若
最后,复制所有
一个 aabab
的 SAM 就建好了!
- Title: 如何手搓一个 SAM
- Author: 11490DX
- Created at : 2025-03-24 21:28:51
- Updated at : 2025-03-25 08:31:12
- Link: https://11490dx.net/2025/03/24/how-to-build-a-sam/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments