[复习] AC自动机

[复习] AC自动机

自动机

从一个状态通过接收一个信号转移到另一个状态。
其实就是从一个点走一种颜色的边到达另一个点,你会有一个初始点,然后每次走当前要走的颜色的边,会走到一个目标点,目标点保存着需要的答案。

AC自动机

Trie 为基础,kmp 的前缀函数思想构建的自动机。

用于解决多模式串匹配等任务。

例题:
给你一个文本串 S,和 n 个模式串 Ti,求每个模式串在文本串中出现了几次。
|S|2105,n2105,Ti2105

我们不能做 nkmp,所以把它“合成一次做”。

考虑把每个模式串插入 Tire 上。

每个节点是一个前缀,对于每个节点 S 维护这个 Trie 上最长的 S 的真后缀,即 border,在这里我们称为失配指针 fail

tr[u][i] 表示 Trie 树的树边,fail[u] 为失配指针。

  • 对于 u 没有的边 i,我们给它重新连向 tr[fail[u]][i]

  • 而如果有这条出边,那么得到 tr[u][i]failtr[fail[u]][i]

我们在 triebfs 从而得到这两个数组,当原本就有 tr[u][i] 时,将 trie[u][i] 加入队列。

for(int i=0;i<26;i++){
if(trans[0][i])q.push(trans[0][i]);
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(trans[u][i]){
fail[trans[u][i]]=trans[fail[u]][i];
q.push(trans[u][i]);
}
else trans[u][i]=trans[fail[u]][i];
}
}

这里有个细节就是,第一个字符的 fail 一定为 0,所以要先遍历根的儿子(就像前缀函数要从 2 开始跑一样)。

我们把 Trie 上没有的边都加上了,那现在 tr 数组就是一个转移函数,我们遍历文本串,每新加一个字符就走一条边,如此一来到达的节点就是当前文本串的前缀最长的在 Trie 上的后缀。

我们从一个点一直跳 fail,如果跳到了一个模式串的末尾,那么说明这个模式串是当前文本串前缀的后缀,即是文本串的子串。

我们不用每次跳 fail,这样时间复杂度是不正确的。

注意到 fail 是一棵树,我们可以每次在当前点打上标记,到最后再遍历树统计。

posted @   dengchengyu  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示