把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

AC自动机原理【学习笔记】

概述

A C AC AC自动机是以 T r i e Trie Trie为结构基础, k m p kmp kmp为思想基础建立的,主要用于多模式串匹配。

A C AC AC自动机上,所有的模式串构成一棵 T r i e Trie Trie树,而且利用 k m p kmp kmp的思想,在 T r i e Trie Trie上构造失配指针。

T r i e Trie Trie上的结点表示的是某个模式串的前缀,相当于一种状态,而 T r i e Trie Trie上的边就相当于是状态的转移。

f a i l fail fail指针

先把所有的模式串放到 T r i e Trie Trie,举例如下:

假如说现在要匹配的文本串是 A B C D ABCD ABCD,我们去树上匹配,会经过 2 , 3 , 4 2,3,4 2,3,4号节点匹配到模式串 A B C ABC ABC,然后就不能继续匹配。

如果接下来重新从根结点开始,复杂度会很高,我们可以借用 k m p kmp kmp的思想,跳到 7 7 7去, 7 7 7就是 4 4 4的失配指针。

More officially, f a i l fail fail指针指向 / 模式串的前缀中 / 匹配 / 当前状态的最长后缀。(断句要断好)
也就是说, i i i的失配指针 j j j,满足 r o o t − > j root->j root>j r o o t − > i root->i root>i的一个后缀,而且是所有满足 r o o t − > i = r o o t − > j x root->i=root->j_x root>i=root>jx中最大的那一个 j x j_x jx
9 9 9号点也满足条件,但是那里不是最长后缀,所以我们不跳到那里去。

下面是 f a i l fail fail的求法:
T r i e Trie Trie上当前的节点是 u u u u u u的父亲是 p p p t r i e [ p ] [ c ] = u trie[p][c]=u trie[p][c]=u
假设深度小于 u u u的所有结点的 f a i l fail fail指针都已经求过。

1. t r i e [ f a i l [ p ] ] [ c ] trie[fail[p]][c] trie[fail[p]][c]存在,那么 f a i l [ u ] = t r i e [ f a i l [ p ] ] [ c ] fail[u]=trie[fail[p]][c] fail[u]=trie[fail[p]][c] p p p的最长后缀的位置在 f a i l [ p ] fail[p] fail[p],在 f a i l [ p ] fail[p] fail[p]的位置再加一个字符 c c c就一定 u u u的最长后缀的位置,因为只在一个确定的串后面加上一个字符而已。
2.如果 t r i e [ f a i l [ p ] ] [ c ] trie[fail[p]][c] trie[fail[p]][c]不存在,那么就要一直跳 f a i l fail fail指针(反复横跳),找 t r i e [ f a i l [ f a i l [ p ] ] ] [ c ] trie[fail[fail[p]]][c] trie[fail[fail[p]]][c],直到它存在,然后重复1.
3.如果真的不存在,那么把 f a i l fail fail指向根。

具体可以用 b f s bfs bfs实现(有假设深度小于 u u u的所有结点的 f a i l fail fail指针都已经求过) ,不过实现和刚才的思考过程是反的。
t r [ u ] [ c ] tr[u][c] tr[u][c]可以理解为字典树上的一条边,也可以理解为一种状态转移,表示 u u u加上一个字符 c c c达到的状态。

代码实际上修改了 T r i e Trie Trie的结构,但是使得匹配转移更加完善。它将 fail 指针跳转的路径做了压缩(就像并查集的路径压缩),使得本来需要跳很多次 a i l ail ail针变成跳一次。

匹配函数

f a i l fail fail是最难的部分, f a i l fail fail理解之后求答案就水到渠成了吧。

时间复杂度


【参考:OIwiki】

posted @ 2023-02-10 21:42  Starlight_Glimmer  阅读(34)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end