begin:2019/5/2
update 2020/6/12 更新了LaTeX(咕了好久
感谢大家支持!
AC自动机详细讲解
AC自动机真是个好东西!之前学 K M P KMP KMP被 N e x t Next Next指针搞晕了,所以咕了许久都不敢开AC自动机,近期学完之后,发现AC自动机并不是很难,特别是对于 K M P KMP KMP,个人感觉AC自动机比 K M P KMP KMP要好理解一些,可能是因为我对树上的东西比较敏感(实际是因为我到现在都不会 K M P KMP KMP)。
很多人都说AC自动机是在 T r i e Trie Trie树上作 K M P KMP KMP,我不否认这一种观点,因为这确实是这样,不过对于刚开始学AC自动机的同学们就一些误导性的理解(至少对我是这样的)。 K M P KMP KMP是建立在一个字符串上的,现在把 K M P KMP KMP搬到了树上,不是很麻烦吗?实际上AC自动机只是有 K M P KMP KMP的一种思想,实际上跟一个字符串的 K M P KMP KMP有着很大的不同。
所以看这篇blog,请放下 K M P KMP KMP,理解好 T r i e Trie Trie,再来学习。
前置技能
1. T r i e Trie Trie(很重要哦)
2. K M P KMP KMP的思想(懂思想就可以了,不需要很熟练)
问题描述
给定 n n n个模式串和 1 1 1个文本串,求有多少个模式串在文本串里出现过。
注意:是出现过,就是出现多次只算一次。
默认这里每一个人都已经会了 T r i e Trie Trie。
我们将 n n n个模式串建成一颗 T r i e Trie Trie树,建树的方式和建 T r i e Trie Trie完全一样。
假如我们现在有文本串 A B C D B C ABCDBC ABCDBC。
我们用文本串在 T r i e Trie Trie上匹配,刚开始会经过 2 、 3 、 4 2、3、4 2、3、4号点,发现到 4 4 4,成功地匹配了一个模式串,然后就不能再继续匹配了,这时我们还要重新继续从根开始匹配吗?
不,这样的效率太慢了。这时我们就要借用 K M P KMP KMP的思想,从 T r i e Trie Trie上的某个点继续开始匹配。
明显在这颗 T r i e Trie Trie上,我们可以继续从 7 7 7号点开始匹配,然后匹配到 8 8 8。
那么我们怎么确定从那个点开始匹配呢?我们称 i i i匹配失败后继续从 j j j开始匹配, j j j是 i i i的 F a i l Fail Fail(失配指针)。
构建Fail指针
F a i l Fail Fail的含义
F a i l Fail Fail指针的实质含义是什么呢?
如果一个点 i i i的 F a i l Fail Fail指针指向 j j j。那么 r o o t root root到 j j j的字符串是 r o o t root root到 i i i的字符串的一个后缀。
举个例子:(例子来自上面的图
i:4 j:7
root到i的字符串是“ABC”
root到j的字符串是“BC”
“BC”是“ABC”的一个后缀
所以i的Fail指针指向j
同时我们发现,“ C C C”也是“ A B C ABC ABC”的一个后缀。
所以 F a i l Fail Fail指针指的 j j j的深度要尽量大。
重申一下 F a i l Fail Fail指针的含义:**((最长的(当前字符串的后缀))**在 T r i e Trie Trie上可以查找到)的末尾编号。
感觉读起来挺绕口的蛤。感性理解一下就好了,没什么卵用的。知道 F a i l Fail Fail有什么用就行了。
求 F a i l Fail Fail
首先我们可以确定,每一个点 i i i的 F a i l Fail Fail指针指向的点的深度一定是比 i i i小的。(Fail指的是后缀啊)
第一层的 F a i l Fail Fail一定指的是 r o o t root root。(比深度 1 1 1还浅的只有 r o o t root root了)
设点 i i i的父亲 f a fa fa的