Trie & AC 自动机

本篇为学习笔记

Trie 字典树

先放张来自 OI Wiki 的图——

Trie

可以看到每个节点都有一个编号,每个编号都代表了一个字符串。

节点之间的有向边边上有字符 \((u,v)=c\),即 \(u\) 所代表的字符串在结尾添加 \(c\) 后为 \(v\) 代表的字符串。

一般根节点编号为 \(0\)

对于每个节点,需要存当前节点代表的字符串是否存在(存在的个数)。

AC 自动机

前置知识:自动机。

AC 自动机常用于解决多模式串匹配的任务。

众所周知 KMP 虽然是线性的,但是一次只能匹配一个模式串。而 AC 自动机一次可以匹配多个模式串。

考虑:

  • 对模式串建立 Trie。
  • 从根节点出发,每新增一个字符,就走相应的边。
  • 如果不存在相应边,回到根节点。
  • 如果走到的节点存在,则匹配成功。

但是这样会少匹配。比如如果有模式串 \(\texttt{abe},\texttt{bc}\),文本串 \(\texttt{abcde}\),那么会在 \(\texttt{ab\color{red}{e}}\) 处失配,回到根节点,错失了 \(\texttt{bc}\)

AC 自动机利用一个 fail 指针来辅助多模式串的匹配。

什么是 fail 指针?

它是每个节点都有的指针,指向当前(节点所代表的)字符串的(Trie 上已存在的)最长真后缀

举个例子,上图中 \(12\) 代表 \(\texttt{caa}\),它指向的是 \(5:\texttt{aa}\)。又如 \(10\to 4,13\to 6,14\to 7\cdots\)

那么 fail 指针有什么用?

依然以模式串 \(\texttt{abe},\texttt{bc}\),文本串 \(\texttt{abcde}\) 为例,那么在 \(\texttt{ab\color{red}{e}}\) 处失配后,会跳到代表 \(\texttt{b}\) 的节点,尝试继续匹配。

那么 fail 指针怎么建?

考虑到 fail 指针指向的是最长真后缀,故指向的节点深度一定更高。bfs 解决:

  • 树根先入队
  • 队列非空时,取出队首节点 \(u\),遍历每个字母 \(c\),记 \(u[c]\) 为对应的儿子
    • \(u[c]\) 存在,将 \(u[c].\text{fail}\gets u.\text{fail}[c]\)
    • 反之,\(u[c]\gets u.\text{fail}[c]\)
posted @ 2024-01-19 20:01  Po7ed  阅读(1)  评论(0编辑  收藏  举报