AC自动机详解
概述
AC自动机全称Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法。
考虑这样一个场景,给出L个模式字符串(加总长度为N),以及长度为M大文本,要求从大文本中提取每个模式字符串出现的位置。如果使用KMP算法,时间复杂度将达到O(LM+N),而使用AC自动机可以在O(N+M)时间复杂度内解决这一问题,当L很大时,AC自动机的优势非常明显。
建立AC自动机
AC自动机实际上是前缀树,但是会引入一个与KMP类似的失败转移的概念。我们先为所有模式建立对应的前缀树,之后为每个前缀树结点添加一个指针fail,指向另外一个前缀树中的结点。每个前缀树中的结点实际上都代表了某个模式的一段前缀,我们之后将结点与其对应的前缀等同起来。令结点x的fail指针指向y(y不为x),其中y是x的后缀,且y是所有符合这类条件的结点中深度最大的(前缀长度最大的),我们称y是x的后缀结点,称x是y的伪父,显然伪父的伪父依旧还是伪父。可以很容易证明以x为起点沿着fail指针不断移动,可以遍历所有x的有效后缀,且访问到的结点深度递减。如果无法为结点的fail指针无法找到有效的结点,那么将fail指针指向前缀树的根结点root。
AC自动机的难度在于要如何为每个结点建立fail指针。由于fail指针指向的结点深度必然小于fail指针的持有者,因此可以用DP的思路,我们先为深度较小的结点建立fail指针,再为深度较大的结点建立fail指针。这个过程可以通过广度优先搜索算法实现。要建立x的fail指针,考虑到x.fail.father必然是x.father的某个有效后缀,因此我们可以通过以x.father为起点,沿着fail指针移动以寻找x.fail.father,并从而找到x.fail。这个过程十分类似于KMP中建立跳转表的过程,这里对其具体操作不再赘述。
使用AC自动机
如何使用AC自动机呢?我们维护一个轨迹结点trace,对于每个输入字符c,我们判断trace是否有c号孩子,如果有就将trace设置为其c号孩子,否则我们将trace设置trace.fail,并继续询问,直到trace成为root或者找到了c号孩子。重复上面过程直到读完文本。
若最后trace成功设置为其c号孩子,则我们称访问了c号孩子。可以证明若输入文本T中T[a...b]与某个模式p相匹配,那么当我们读入T[b]时,p和p的所有伪父中有且只有一个结点被访问。*对于任意c<a,a=<d<b,若trace匹配T[c...d],那么当我们读入T[d+1]时,若成功,trace将步进,若失败,则依旧能保证trace转移后c<=a,因为此时p的某个祖先结点已经做好了接盘的准备,故c始终会小于等于a,当c=a时,此时trace为p的祖先,因此直到读入T[b]时,trace必定匹配T[c...b],此时c<=a,因此trace是p或p的伪父。*通过这段证明我们基本可以了解到如何在AC自动机读取完文本后获取我们想要的结果,如果需要每个模式出现次数,可以得知每个模式的出现次数为其被访问次数加上其所有伪父被访问次数,而如果需要每个模式的匹配位置,思路也是类似,为每个模式维护被访问时读取字符的下标就可以了,整合上所有伪父的匹配位置即可得出。
时间复杂度
时间复杂度分为建立AC自动机的时间复杂度和匹配的时间复杂度。
设所有模式的长度和为n,文本长度为m。建立前缀树的时间复杂度为O(n),而建立fail指针的时间复杂度分析类似于KMP算法中建立跳转表的时间复杂度。我们可以定义每个结点x的fail指针指向的y结点的深度为x的“子深”,记作x.cd。很容易发现x.cd<=x.father.cd+1,而我们每次从x.father出发沿着fail指针移动,x的子深也在不断递减但不会低于0,在为某个模式上的结点建立fail时,每次后移最多提供1个子深,因此在创建模式pi时我们最多沿着fail指针移动了|pi|次,故创建所有模式总共沿着fail指针最多移动O(n)次,到此说明了建立fail指针的时间复杂度为O(n)。
对模式匹配,每当我们读入一个字符c时,trace或者向下移动(即有c号孩子)并结束或者沿着fail移动到某个自己的后缀上去。显然向下移动最多发生O(m)次,而沿着fail移动,就如同我所说的每次都必定会降低子深,而每次向下移动可以提供最多1子深,因此可以保证沿着fail移动的次数最多为O(m)次。故总的时间复杂度为O(m)。
时间复杂度的总和为O(n+m),空间复杂度为O(Cn),其中C为使用的字符集的大小(用于建立前缀树)。
AC自动机详解的更多相关文章
- [转] AC自动机详解
转载自:http://hi.baidu.com/nialv7/item/ce1ce015d44a6ba7feded52d AC自动机详解 AC自动机是用来处理多串匹配问题的,即给你很多串,再给你一篇文 ...
- Aho-Corasick 多模式匹配算法、AC自动机详解
Aho-Corasick算法是多模式匹配中的经典算法,目前在实际应用中较多. Aho-Corasick算法对应的数据结构是Aho-Corasick自动机,简称AC自动机. 搞编程的一般都应该知道自动机 ...
- AC自动机详解(附加可持久化AC自动机)
AC自动机 AC自动机,说白了就是在trie树上跑kmp(其实个人感觉比kmp容易理解).是一种多匹配串,单个主串的匹配.概括来说,就是将多个匹配串构造一个trie树,对于每个trie树的节点构造nx ...
- AC自动机详解 (P3808 模板)
AC自动机笔记 0.0 前言 哇,好久之前就看了 KMP 和 Trie 树,但是似乎一直没看懂 AC自动机?? 今天灵光一闪,加上之前看到一些博客和视频,瞬间秒懂啊... 其实这个玩意还是蛮好理解的. ...
- 【转】AC算法详解
原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...
- hdu-Danganronpa(AC自动机)
Problem Description Danganronpa is a video game franchise created and developed by Spike Chunsoft, t ...
- 算法模板——AC自动机
实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...
- 病毒侵袭---hdu2896(AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896 输入的字符是所有可见的ASCII码(共有127个)所以要注意一下: 把结果存到一个数组中,然后输 ...
- 学习笔记:AC自动机
话说AC自动机有什么用......我想要自动AC机 AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配 ...
随机推荐
- [置顶]
Android App引导页这些坑你自己犯过吗?
场景:测试机:华为荣耀6x 今天我自己掉入一个很蠢蠢的坑,一个引导页搞了20多分钟,不管我怎么测试用真机还是模拟器都无法运行,但是我写的demo完全没问题,好无语,我都怀疑我是不是搞android,我 ...
- ajax函数里不能用this调用
ajax函数里不能用this调用,想用的话,在ajax外面弄个变量var mythis = $(this),然后在里面用就行了 因为,在ajax方法里写$(this)指向的是最近调用它的jquery对 ...
- 跟我学Delphi Xe4 开发 IOS 一 , 重读Delphi Xe4 自带文档.
安装了 Delphi Xe4 之后打开这个地址就是完整的官方的文档了. 虽然不是立刻能解决你的问题. 但也是必须要看一遍的. 最基础的都在这里了. ms-help://embarcadero.rs_x ...
- phpwind主要表结构的研究随笔[1]
最近计划做一个新闻网站,前端打算用成熟的CMS搭建,后台是mongodb+mysql做数据过滤容器和最终数据存储,选型CMS如下: dedecms:国内某知名cms,以前用过,功能强大,网上资料资料很 ...
- 封装Socket.BeginReceive/EndReceive以支持Timeout
Socket .NET中的Socket类提供了网络通信常用的方法,分别提供了同步和异步两个版本,其中异步的实现是基于APM异步模式实现,即BeginXXX/EndXXX的方式.异步方法由于其非阻塞的特 ...
- webpack+vue-cli搭建项目 (vue项目重构三)
在自己的电脑下载了npm 与 node的情况下 可使用vue-cli快速构建vue项目执行命令如下: # 全局安装 vue-cli$ npm install -g vue-cli# 创建一个基于 &q ...
- 洛谷 1291 [SHOI2002]百事世界杯之旅
题目:https://www.luogu.org/problemnew/show/P1291 大水题!套路!模板! 稍微注意一下输出就行了. #include<iostream> #inc ...
- 织梦 dede 笔记
将项目转移到另一服务器 方法: https://www.genban.org/news/dedecms-13096.html 在实际中,我走的是第二种方法 方法一: 1 后台>系统>备份 ...
- 字符串(PHP学习)
1.什么是字符串 答:一串字符组成(参考羊肉串) 2.字符串定义 答:单引号,双引号,包含单引号或双引号的字符串(1.双引号里面有单引号2.单引号里面有双引号3.转义4.字符拼接) 3.单双引号定义字 ...
- 不常用的linux命令
不太常用的命令 vipw ##打开密码配置文件 dmesg ##补充说明:kernel会将开机信息存储在ring buffer中.您若是开机时来不及查看信息,可利用dme ...