定义
AC 自动机实际上就是在 Trie 树之上,加了类似 KMP 的 next 数组,只不过此处的 next 数组是构建在树上罢了。
构建AC 自动机包含两个操作:
- 将多个模式串构建成 Trie 树;
- 在 Trie 树上构建失败指针(相当于 KMP 中的失效函数 next 数组)。
下面链接讲得更加清晰:
https://www.bilibili.com/medialist/play/ml1213813670/BV1uJ411Y7Eg
复杂度分析
构建Trie树
Trie 树构建的时间复杂度是 O(m*len),其中 len 表示敏感词的平均长度,m 表示敏感词的个数。
构建失败指针
假设 Trie 树中总的节点个数是 k,每个节点构建失败指针的时候,每个节点构建失败指针的时间复杂度是 O(len)。整个失败指针的构建过程就是 O(k*len)。AC 自动机的构建过程都是预先处理好的,构建好之后,并不会频繁地更新,不会影响到敏感词过滤的运行效率。
AC 自动机匹配
for 循环依次遍历主串中的每个字符,for 循环内部的时间复杂度也是 O(len),所以总的匹配的时间复杂度就是 O(n*len)。因为敏感词并不会很长,而且这个时间复杂度只是一个非常宽泛的上限,实际情况下,可能近似于 O(n)。失效指针可能大部分情况下都指向 root 节点,所以绝大部分情况下,在 AC 自动机上做匹配的效率要远高于刚刚计算出的比较宽泛的时间复杂度。只有在极端情况下,AC 自动机的性能才会退化的跟 Trie 树一样。
《数据结构与算法之美》 -- 王争