继续填坑.
本来想把这三个玩意分开来写的,后来发现其实阿次自动姬就可以描述这几个的原理了.
那就写一起了.
KMP
全称叫做 (Knuth-Morris-Pratt).是能够在线性时间内完成字符串匹配的算法.
原理
KMP算法不同于一般的暴力匹配算法的地方在于,KMP算法充分利用了每次匹配后的失配信息,不会每一次都从第一个位置匹配,因此我们先介绍一个玩意叫做适配数组fail[i]
.
对于fail[i]
数组的定义:
模式串中前i
个字符作为目标串的最大前后缀对称长度.
这什么定义啊看得我头大.
我们以实际栗子来说明.
假设现在又这样的一个模式串shryshrkrin
根据定义我们推出的fail
数组为00001230000
为什么这么定义fail数组呢?在我们匹配字符串的时候,如果之前的匹配失败了,我们直接用fail数组得到下一个合法的前缀即可.而且又可以证明,fail数组和匹配的串没有任何的关系,换言之,得到了fail数组,就是得到了失配信息.与下一个可能合法的字符串的位置.
好我们是不是只要能求出fail
数组就可以收工了?
fail
的递推方式如下.
- 如果
fail[i - 1]
不为 0,且第i
个字符与第fail[i - 1] + 1
个字符相同,则fail[i]
即为fail[i - 1] + 1
; - 如果
fail[i - 1]
为 0,且第i
个字符与首个字符相同,则fail[i] = 1
,否则fail[i] = 0
; - 如果
fail[i - 1]
不为 0,且第i
个字符与第fail[i - 1] + 1
个字符不同,则继续对比第i
个字符与fail[fail[i - 1]] + 1
个字符,一直向前找直到匹配或者找到了 0。
板子
1 |
|
然后是板子题.
板子题,求第一个串在第二个中的出现次数.
1 | //#include<bits/stdc++.h> |
还是板子题,求询问串的所有出现位置与next数组.
1 |
|
那么再来一道.
算了看习题整理吧。
Trie树(字典树)
其实是个很斯波的东西.
很好写也很好懂.
求询问串为模式串前缀的个数.
1 |
|
对字符串查询操作.求询问串作为前缀是否出现,是否第一次出现,是否没出现.
1 |
|
Aho-Corasick Automaton
这玩意才是重点
首先我对于AC自动姬的理解就是
一样的对于模式串建立字典树,在树上算fail数组,我们把这两个玩意放到一起.
Trie只能做前缀不能匹配吧,加了KMP不就行了么!
我觉得有张图挺好的。
这是普通的建立Trie树的过程
然后我们在上面加上fail数组 / 指针就可以了
对于AC自动姬,有两种写法
带指针(我还是偏向于喜欢这么写,感觉挺好理解的)
可食用对象
1 |
|
网上拉来一个不用指针的.
1 |
|