AC自动机 算法详解(图解)及模板
要学AC自动机需要自备两个前置技能:KMP和trie树(其实个人感觉不会kmp也行,失配指针的概念并不难)
其中,KMP是用于一对一的字符串匹配,而trie虽然能用于多模式匹配,但是每次匹配失败都需要进行回溯,如果模式串很长的话会很浪费时间,所以AC自动机应运而生,如同Manacher一样,AC自动机利用某些操作阻止了模式串匹配阶段的回溯,将时间复杂度优化到了O(n)O(n)O(n)(n)为文本串长度
转载注明出自bestsort.cn,谢谢合作
大家回复请去bestsort.cn回复吧,CSDN我每次都不知道你们回复的楼层在哪...点击查看评论它都不带自动跳转的QAQ
下面开始用图学习ac自动机吧(个人比较喜欢放图,能用一张图解决的绝不叨叨)
首先给定模式串"ash","shex","bcd","sha"
,然后我们根据模式串建立如下trie树:
然后我们再了解下一步:
ac自动机,就是在tire树的基础上,增加一个fail指针,如果当前点匹配失败,则将指针转移到fail指针指向的地方,这样就不用回溯,而可以路匹配下去了.(当前模式串后缀和fail指针指向的模式串部分前缀相同,如abce
和bcd
,我们找到c
发现下一个要找的不是e
,就跳到bcd
中的c
处,看看此处的下一个字符(d
)是不是应该找的那一个)
一般,fail指针的构建都是用bfs实现的
首先每个模式串的首字母肯定是指向根节点的(一个字母你瞎指什么指,指了也是头字母有什么用嘛)
现在第一层bfs遍历完了,开始第二层
(根节点为第0层)第二层a
的子节点为s
,但是我们还是要从a-z
遍历,如果不存在这个子节点我们就让他指向根节点(如下图红色的a
)
当我们遍历到s
的时候,由于存在s
这个节点,我们就让他的fail指针指向他父亲节点(a
)的fail指针指向的那个节点(根
)的具有相同字母的子节点(第一层的s
),也就是这样
按照相同规律构建第二层后,到了第三层的h
点,还是按照上面的规则,我们找到h
的父亲节点(s
)fail指针指向的那个位置(第一层的s
)然后指向它所指向的相同字母根->s->h
的这个链的h
节点,如下图
完全构造好后的树
然后匹配就很简单了,这里以ashe
为例
我们先用ash
匹配,到h
了发现:诶这里ash
是一个完整的模式串,好的ans++
,然后找下一个e
,可是ash
后面没字母了啊,我们就跳到h
fail指针指向的那个h
继续找,还是没有?再跳,结果当前的h
指向的是根节点,又从根节点找,然而还是没有找到e
,程序END
过程如下图
喜闻乐见模板系列
#include <queue>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2*1e6+9;int trie[maxn][26]; //字典树
int cntword[maxn]; //记录该单词出现次数
int fail[maxn]; //失败时的回溯指针
int cnt = 0;void insertWords(string s){int root = 0;for(int i=0;i<s.size();i++){int next = s[i] - 'a';if(!trie[root][next])trie[root][next] = ++cnt;root = trie[root][next];}cntword[root]++; //当前节点单词数+1
}
void getFail(){queue <int>q;for(int i=0;i<26;i++){ //将第二层所有出现了的字母扔进队列if(trie[0][i]){fail[trie[0][i]] = 0;q.push(trie[0][i]);}}//fail[now] ->当前节点now的失败指针指向的地方
tire[now][i] -> 下一个字母为i+'a'的节点的下标为tire[now][i]while(!q.empty()){int now = q.front();q.pop();for(int i=0;i<26;i++){ //查询26个字母if(trie[now][i]){//如果有这个子节点为字母i+'a',则
//让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)//有点绕,为了方便理解特意加了括号fail[trie[now][i]] = trie[fail[now]][i];q.push(trie[now][i]);}else//否则就让当前节点的这个子节点//指向当前节点fail指针的这个子节点trie[now][i] = trie[fail[now]][i];}}
}int query(string s){int now = 0,ans = 0;for(int i=0;i<s.size();i++){ //遍历文本串now = trie[now][s[i]-'a']; //从s[i]点开始寻找for(int j=now;j && cntword[j]!=-1;j=fail[j]){//一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).ans += cntword[j];cntword[j] = -1; //将遍历国后的节点标记,防止重复计算}}return ans;
}int main() {int n;string s;cin >> n;for(int i=0;i<n;i++){cin >> s ;insertWords(s);}fail[0] = 0;getFail();cin >> s ;cout << query(s) << endl;return 0;
}
AC自动机 算法详解(图解)及模板相关推荐
- 极限定律 My Algorithm Space AC自动机算法详解
转载自:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html 首先简要介绍一下AC自动机:Aho-Corasick automatio ...
- AC自动机算法详解以及Java代码实现
详细介绍了AC自动机算法详解以及Java代码实现. 文章目录 1 概念和原理 2 节点定义 3 构建Trie前缀树 3.1 案例演示 4 构建fail失配指针 4.1 案例演示 5 匹配文本 5.1 ...
- KMP算法详解P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- 【算法详解】背包模板或模型详解
01背包 有N 件物品和一个容量为V 的背包.放入第i 件物品耗费的空间 是vi,得到的价值是wi.求解将哪些物品装入背包可使价值总和最大. 根据题意,我们便可以设f[i][j]为已经装了i件物品且最 ...
- Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现
多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...
- AC自动机算法及模板
AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报 分类: AC自动机(1) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...
- 图论-最短路Dijkstra算法详解超详 有图解
整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...
- 图解机器学习算法(13) | 聚类算法详解(机器学习通关指南·完结)
作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/34 本文地址:https://www.showmeai.tech/article-d ...
- 区块链技术用解决拜占庭将军问题_两军问题_拜占庭将军问题详解图解算法
两军问题 我们来看一下好处理器的情况,但通信线路有问题.这就是所谓的两军问题,可以概括如下: A,B 两军师协同攻击敌军C, A和B在物理上是分开的,并使用信使进行通信. A向B发送一个消息" ...
最新文章
- 亚里士多德千年前的猜想,被这群MIT本科生向前推进了一步
- 设计模式——装饰者模式
- linux中文输入法的实现
- 下面不属于python保留字_下面不属于Python保留字的是:?????????????????????????????????...
- 《面向对象分析与设计》一3.2 参与者
- ubuntu10.04下安装Eclipse
- 2011年吉林大学计算机研究生机试真题
- Unity WebGL与IIS小坑
- dubbo常用类和路径
- 聊聊身边的嵌入式—英语学习利器点读笔
- 计算机界面没磁盘驱动器,驱动器中没有磁盘的原因和解决办法
- java开发手册-阿里巴巴2020最新版
- 歌乎:985博士生对996的困惑
- 电子工程师是怎样的成长之路?
- 十大数据挖掘领域的经典算法
- fd leak问题查找(Android)
- Git远程仓库配置SSH(以github为例)
- Django基础-中文文档
- 紫书已经基本学完现在开启紫书题目补完计划!!!
- you-get下载神器的安装和使用