标准KMP算法用于单一模式串的匹配,即在母串中寻求一个模式串的匹配,但是现在又存在这样的一个问题,如果同时给出多个模式串,要求找到这一系列模式串在母串存在的匹配个数,我们应该如何处理呢?

基于KMP算法,我们能够想到的一个朴素算法就是,枚举这多个模式串,然后进行多次KMP算法,这个过程中完成计数,假设这里有n个模式串,那么整个算法的复杂度大约是O(n*m),m是母串的长度,这里的时间复杂度是粗略估计,没有计算辅助数组的时间(KMP中的next数组),但是这种复杂度还是太高,没有做到KMP算法中“成分利用已知信息”的核心思想,这里有一个巧妙的算法——AC自动机,能够线性的完成多模式串的匹配,即时间复杂度能够优化到O(m)。

下面简单的介绍一下解决多模式串匹配问题的AC自动机算法的思想。

回想起KMP所呈现的思想,我们在匹配之前需要充分挖掘模式串中所蕴含的信息,我们通过求得模式串的next数组,使得我们在遍历母串的时候得到了极大的优化,那么这里对于多模式串的匹配,应该采取相同的思路,我们应该对多个模式串所蕴含的信息进行充分挖掘。

由多模式串朴素的二维数组的存储,为了节省空间,我们又会联想到之前的字典树,这里我们基于多个模式串,建立一个字典树,然后线性扫母串的时候,就是在这样一个字典树上扫。

再次回想KMP中匹配过程,求得next数组时候,我们在母串上移动模式串完成匹配,基于next数组,我们得到的优化使得在模式串匹配失败之后,能够极大限度的往母串的右侧移动同时能够保证不漏掉任何匹配情况。但是在AC自动机这里,做法上有点区别,但是思想是一致的。做法上的区别体现在,基于多模式串的字典树上,我们将母串在字典树上进行匹配,我们在构造字典树的时候,记录模式串的最后一个字符作为终止节点,那么母串在字典树上匹配到终止节点的时候,就表明完成了一个模式串的匹配。

那么现在我们需要完成的就是匹配失败后的优化,在母串区间str[i]~str[j]匹配失败以后,最优的做法应该是,求得str[i]~str[j]这段字符串最长的公共前缀和与后缀和,然后继续从这个最长的前缀和这条支路下,继续进行匹配。为了完成这一步“极大限度的往母串的右侧移动同时能够保证不漏掉任何匹配情况”,我们在字典树每个节点处设置一个“匹配失败跳转”指针(下文统称fail指针),记录如果在该点匹配失败,最优化的情况下我们应该跳转到的字典树的位置。

能够看到,整个AC自动机呈现的多模式串匹配其实和KMP算法是高度的相似的。

那么下面就需要解决的问题就是,就像计算KMP中的next数组,这里我们如何计算字典树里的fail指针。

假设我们当前在找vi的fail指针,那么很显然,我们去找vi的父节点的fail指针所指向的节点vp,根据该指针的定义,很容易看到:

(1)    如果当前节点vp的子节点vj能够与vi匹配,那么vi的fail指针必然指向vj。

(2)    如果当前节点vp的子节点没有能够与vi匹配的,那么我们需要去找vp的fail指针指向的节点的子节点,看是否有与vi相互匹配的,没有的话,循环操作。

对于(2)似乎形成了一个递归模式,为什么会这样呢?或者说这样做的正确性体现在哪里呢?它源于fail指针的定义,仔细的读者应该能够看到,fail指针本质上是一个描述一个字符串最长的公共前缀与后缀,对于一段字符串str[i]~str[j],失配之后我们在该段字符串最长公共前后缀(记作str[p]~str[j])的基础上,添加那个导致失配的字符a,但是字典树中可能不存在这种情况,难道我们就因此重新开始新的匹配么?当然不,我们再找一下字符串str[p]~str[j]的最长公共前后缀(记作str[k]~str[j]),添加那个导致失配的字符a,然后循环操作……

这就是解决AC自动机的一个简答的思想描述。

能够看到它与KMP算法思想同步到了一致,这启示我们学习过程中的触类旁通,这种现象在很多地方也有着很明显的体现(积分、二重积分、三重积分;一元函数、多元函数;单一变量分布、多变量联合分布)。很多思维思想在一维的角度建立,然后推广到二维角度甚至更高维度。

AC自动机——多模式串匹配的算法思想的更多相关文章

  1. AC 自动机——多模式串匹配

    网站上的敏感词过滤是怎么实现的呢? 实际上,这些功能最基本的原理就是字符串匹配算法,也就是通过维护一个敏感词的字典,当用户输入一段文字内容后,通过字符串匹配算法来检查用户输入的内容是否包含敏感词. B ...

  2. AC自动机 - 多模式串匹配问题的基本运用 + 模板题 --- HDU 2222

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  3. Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例

    摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ...

  4. AC自动机 - 多模式串的匹配运用 --- HDU 2896

    病毒侵袭 Problem's Link:http://acm.hdu.edu.cn/showproblem.php?pid=2896 Mean: 略 analyse: AC自动机的运用,多模式串匹配. ...

  5. AC自动机 - 多模式串的匹配 --- HDU 3695 Computer Virus on Planet Pandora

    Problem's Link Mean: 有n个模式串和一篇文章,统计有多少模式串在文章中出现(正反统计两次). analyse: 好久没写AC自动机了,回顾一下AC自动机的知识. 本题在构造文章的时 ...

  6. AC自动机 - 多模式串的匹配运用 --- HDU 3065

    病毒侵袭持续中 Problem's Link:http://acm.hdu.edu.cn/showproblem.php?pid=3065 Mean: 略 analyse: AC自动机的运用. 这一题 ...

  7. (转)两种高效过滤敏感词算法--DFA算法和AC自动机算法

    原文:https://blog.csdn.net/u013421629/article/details/83178970 一道bat面试题:快速替换10亿条标题中的5万个敏感词,有哪些解决思路? 有十 ...

  8. HDU 2222:Keywords Search(AC自动机模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 KMP是单模式串匹配的算法,而AC自动机是用于多模式串匹配的算法.主要由Trie和KMP的思想构成. 题意 ...

  9. AC自动机基础知识讲解

    AC自动机 转载自:小白 还可参考:飘过的小牛 1.KMP算法: a. 传统字符串的匹配和KMP: 对于字符串S = ”abcabcabdabba”,T = ”abcabd”,如果用T去匹配S下划线部 ...

随机推荐

  1. 优化有标量子查询的SQL

    数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...

  2. js学习--DOM操作详解大全二(window对象)

    一.window - 计时器 1、setTimeout()可以用来在指定的时间之后单次调用函数.setTimeount(f,1000);//一秒后调用函数fclearTimeout();取消函数的执行 ...

  3. Python 学习之urllib模块---用于发送网络请求,获取数据(2)

    接着上一次的内容. 先说明一下关于split()方法:它通过指定分隔符对字符串进行切片,如果参数num 有指定值,则仅分隔 num 个子字符串(把一个字符串分割成很多字符串组成的list列表) 语法: ...

  4. 【python】python支持中文变量,醉了

    哈哈 = 1 呜呜 = -1 哈哈 + 呜呜 = 0

  5. css 多出一行或多行后显示...的方法

    一行超出显示... .mui-ellipsis { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } 两行超出的显示. ...

  6. [转]IoC框架

    1 IoC理论的背景     我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.   图1:软件系统中耦合的对象 如果 ...

  7. JsRender

    JsRender 不少前端人员应该都用过,它是一个比较强大的模板,不牵涉太多技术依赖,使用起来非常舒服.我本人在前端开发中使用React之前,都是用的它了(实际上我感觉React没有JsViewes好 ...

  8. 移动端meta标签整理-备

    分类 在介绍移动端特有 meta 标签之前,先简单说一下 HTML meta 标签的一些知识. meta 标签包含了 HTTP 标题信息 (http-equiv) 和 页面描述信息 (name). h ...

  9. Javascript异步编程的4种方法(转载)

    原博地址: http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

  10. 用C++实现绘制标尺的方法,使用了递归

    在这个例子当中将使用递归来实现一个打印标尺刻度的方法.首先是递归,函数调用其本身就叫递归,在需要将一项工作不断分为两项较小的.类似的工作时,递归非常有用,递归的方法被称为分而治之策略. 下面是一个wi ...