概述

  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自动机详解的更多相关文章

  1. [转] AC自动机详解

    转载自:http://hi.baidu.com/nialv7/item/ce1ce015d44a6ba7feded52d AC自动机详解 AC自动机是用来处理多串匹配问题的,即给你很多串,再给你一篇文 ...

  2. Aho-Corasick 多模式匹配算法、AC自动机详解

    Aho-Corasick算法是多模式匹配中的经典算法,目前在实际应用中较多. Aho-Corasick算法对应的数据结构是Aho-Corasick自动机,简称AC自动机. 搞编程的一般都应该知道自动机 ...

  3. AC自动机详解(附加可持久化AC自动机)

    AC自动机 AC自动机,说白了就是在trie树上跑kmp(其实个人感觉比kmp容易理解).是一种多匹配串,单个主串的匹配.概括来说,就是将多个匹配串构造一个trie树,对于每个trie树的节点构造nx ...

  4. AC自动机详解 (P3808 模板)

    AC自动机笔记 0.0 前言 哇,好久之前就看了 KMP 和 Trie 树,但是似乎一直没看懂 AC自动机?? 今天灵光一闪,加上之前看到一些博客和视频,瞬间秒懂啊... 其实这个玩意还是蛮好理解的. ...

  5. 【转】AC算法详解

    原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...

  6. hdu-Danganronpa(AC自动机)

    Problem Description Danganronpa is a video game franchise created and developed by Spike Chunsoft, t ...

  7. 算法模板——AC自动机

    实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...

  8. 病毒侵袭---hdu2896(AC自动机)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896 输入的字符是所有可见的ASCII码(共有127个)所以要注意一下: 把结果存到一个数组中,然后输 ...

  9. 学习笔记:AC自动机

    话说AC自动机有什么用......我想要自动AC机 AC自动机简介:  首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配 ...

随机推荐

  1. Tomcat应用服务器被黑客 肉鸡攻击 记录

    线上一台应用服务器报警,负载过高,这个就诡异了,因为只是一个普通的服务器,应用使用人员不到10个人,咋会负载高,肯定有问题哪,登陆上去查看, top查看哪个占据的cpu资源比较多 [root@aew0 ...

  2. BaseCommand

    import java.io.Serializable; import android.util.Log; public class BaseCommand implements Serializab ...

  3. 转载 关于include尖括号和双引号的区别。

    对于使用尖括号( < >),预处理程序cpp在系统预设包含文件目录(如/usr/include)中搜寻相应的文件,而对于使用双引号(“ ”),cpp在当前目录中搜寻头文件,这个选项的作用是 ...

  4. niosii boot过程

    1 概述Nios II 的boot过程要经历两个过程. FPGA器件本身的配置过程.FPGA器件在外部配置控制器或自身携带的配置控制器的控制下配置FPGA的内部逻辑.如果内部逻辑中使用了Nios II ...

  5. is is not == !=之间的区别

    简单来说,python中的is与is not运算符可判断两个对象是否为同一对象.若为同一个对象,则对象1 is 对象2为True .反正,若非同一个对象,则对象1 is not 对象2为True 要理 ...

  6. django的manytomany总结

    from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagli ...

  7. xcomponent web 跨域组件介绍

    1. 项目地址: https://github.com/krakenjs/xcomponent 2. 支持的特性 a. Render an iframe or popup on a different ...

  8. gatsbyjs 了解

    1.  模型 2. 总结&&资料 从模型上可以看出和jamstack 提出的架构模型比较相似,可以看成是一个具体的实现,功能还是比较强大的 https://www.gatsbyjs.o ...

  9. c&c++ datetime

    时间函数之间的关系 struct tm { int tm_sec; // 代表目前秒数,正常范围0-59,但允许至61秒: int tm_min; // 代表目前分数,范围为0-59. int tm_ ...

  10. 关于yii2的中文乱码问题

    在数据库配置中这么配就可以了 <?php return [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=127.0.0. ...