AC自动机详解

AC自动机(算法介绍) 前言: ac自动机能帮你自动通过ac题目(才怪),其实所谓的ac自动机他并不能帮你自动ac,而是一种多模式串的匹配算法.相较于kmp算法在运行多模式串的匹配时只需一次遍历即可,而kmp要针对不同的子序列对母序列进行多次遍历. 简介: ac自动机是通过预处理所要查找的所有子序列 ... 阅读详情

前置芝士

KMP字符串匹配算法

Trie树(字典树)

引入

来看一道题目:(洛谷 P3808 【模板】AC自动机(简单版))

给定 n n n 个模式串 s i s_i si​ 和一个文本串 t t t,求有多少个不同的模式串在文本串里出现过。

你想到了什么?

KMP?KMP用来处理单模匹配问题有奇效,但是解决这道题么。。。

妥妥的T飞

这就要用到一种神奇 难 的算法:AC自动机了!(充满诱惑力的名字)

AC自动机

Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法。——百度百科

首先我们将所有模式串存入Trie树,存入的方式与单独的Trie一模一样。

比如我们加入"ask",“skex”,“bhd”,“ska”:
请添加图片描述

然后,我们开始跑AC自动机了!其实,AC自动机就是在Trie树上做KMP。

我们来复习一下KMP的做法,首先要处理nxt。nxt在KMP中的意义是什么呢?是模式串的每个子串的最长公共前后缀。那nxt有什么作用呢?可以避免失配后的从头匹配。举个例子:

我们有一个模式串"ababa",我们处理出它的nxt:

ababa
00012

我们放到文本串"ababcababa"中匹配:

请添加图片描述

当匹配到c时失配,而这时c前面的abab已经匹配过了,这时我们就可以跳到nxt上继续匹配:
请添加图片描述
仍然失配,跳到nxt:
请添加图片描述
失配,跳:

请添加图片描述
匹配成功,结束。

为什么可以这样呢?因为我们每次失配前,都已经匹配过一段,如果有与这一段相同的部分就不用再匹配了,也就是我们的跳nxt。

好了,KMP复习完了,我们可以发现,进行多模匹配时,也会有两个串之间相同的部分,所以,我们可以在Trie树上使用nxt。

那么,Trie树上的nxt有什么作用呢?我们来看一看:

假设我们已经匹配完了ask:
请添加图片描述

按照以前的做法,我们应该回到根,重新匹配。然而,我们可以发现,ask中的"sk"与skex以及ska中的"sk"相同!我们可以选择直接跳过去:

请添加图片描述

这样,我们就不用再匹配依次"sk"了!

那这么神奇的功能是怎么实现的呢?

神奇海螺告诉我们,只需要使用bfs!

首先,我们让 第 一 层 {\color{red}{第一层}} 第一层的节点的nxt全部指向根:

请添加图片描述
开始遍历 第 二 层 {\color{limegreen}{第二层}} 第二层。对于节点s,我们让它的nxt指向它的父亲节点的nxt的具有相同字母的儿子:

请添加图片描述

第 二 层 {\color{limegreen}{第二层}} 第二层遍历后如下:

请添加图片描述

我们以刚才的规律,继续遍历 第 三 层 {\color{gold}{第三层}} 第三层:
请添加图片描述

第 四 层 {\color{blue}{第四层}} 第四层:

请添加图片描述

(好像有一点点乱)

这样,我们nxt就处理好了。我们现在可以把文本串放上去跑了:

以"askex"为例,我们匹配到k时,发现没有e了,就跳到k的nxt上继续匹配,一直匹配到x,结束。

但是,我们跳到nxt上之后,如果这个节点仍然不存在呢?我们要继续跳nxt,一直跳到存在或到达根节点为止?

是不是觉得像这样一直跳太麻烦了,而且消耗时间。有没有办法优化一下呢?

我们可以发现,对于任意一个节点,它的nxt一定比它要先处理到(因为它们不在一层),我们是不是可以在bfs的时候将每个节点的nxt直接接到最后的nxt上呢?

经过 抄袭 思考后,我们发现,对于所有不存在的节点,我们才会去跳nxt(因为不存在表示当前失配),而对于不存在的节点,它在Trie树上是没有记录的。所以我们可以将Trie树上一个节点的不存在的儿子给标记为这个节点的nxt的儿子(强行认爹)。这时,我们修改了Trie树,所以Trie树已经不再是树了,而是一张图,我们称之为Trie图。

至此,我们的Trie树在神奇海螺的指引下强行认爹,成功进化。进化成的Trie图就可以用来跑文本串了!

完整代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,tot=1;
string s,str;
struct trie
{
	int b;
	int ch[26];
	int nxt;
}
t[500010];
void insert(string s)
{
	int p=1;
	for(int i=0;i<s.length();i++)
	{
		if(!t[p].ch[s[i]-'a'])
			t[p].ch[s[i]-'a']=++tot;
		p=t[p].ch[s[i]-'a'];
	}
	t[p].b++;
}
void bfs()//处理nxt
{
	queue<int> q;
	for(int i=0;i<26;i++)
		t[0].ch[i]=1;//将0节点接到1,便于跳nxt
	q.push(1);
	t[1].nxt=0;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		int f=t[u].nxt;
		for(int i=0;i<26;i++)
		{
			int v=t[u].ch[i];
			if(!v)//若儿子不存在
				t[u].ch[i]=t[f].ch[i];//强行认爹
			else
			{
				t[v].nxt=t[f].ch[i];//储存nxt
				q.push(v);//入队,继续bfs
			}
		}
	}
}
int search(string s)
{
	int p=1,ans=0;
	for(int i=0;i<s.length();i++)
	{
		int k=t[p].ch[s[i]-'a'];
		while(k>1&&t[k].b!=-1)//不断匹配,直到匹配到根
		{
			ans+=t[k].b;
			t[k].b=-1;
			k=t[k].nxt;
		}
		p=t[p].ch[s[i]-'a'];
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		cin>>str;
		insert(str);
	}
	bfs();
	cin>>s;
	printf("%d\n",search(s));
	return 0;
}
洛谷 P3808 【模板】AC 自动机(简单版) AC 自动机模板 阅读详情

相关推荐

AC自动机初步入门详解

前言 AC自动机(Aho-Corasick automaton)是KMP的升级版。KMP是单模匹配算法,处理在一个文本串中查找一个模式串的问题;AC自动机是多模匹配算法,能在一个文本串中同时查找多个不同的模式串。 多模块匹配问题:给定一个长度为n的文本S,以及k个平均长度为m的模式串P1,P2,…,Pn,要求搜索这些模式串出现的位置。 其实用KMP也能解决多模匹配问题,缺点是复杂度较高,需要对每个...

weixin_43888067的博客 746

AC自动机详解,原理、优化分析,代码实现

填坑ing

EQUINOX1的博客 9486

[置顶]AC自动机-算法详解

What's Aho-Corasick automaton?   一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一。   简单的说,KMP用来在一篇文章中匹配一个模式串;但如果有多个模式串,需要在一篇文章中把出现过的模式串都匹配出来,就需要Aho-Corasick automaton算法了。 My Understanding About Aho-Coras

北岛知寒 1万+

关于 AC 自动机

AC 自动机,全称 Aho-Corasick 自动机,是一种用于字符串搜索的算法,由 Alfred V. Aho 和 Margaret J. Corasick 在 1975 年提出。这个算法是为了解决在一个主文本字符串中查找多个模式字符串(或称为“关键词”)的问题,它可以在线性时间内完成搜索,非常高效。在计算机科学中,Aho-Corasick 算法是 Alfred V. Aho 和 Margaret J. Corasick 于 1975 年发明的一种字符串搜索算法。

weixin_43501634的博客 5445

[ESP32]:基于esp-modbus实现serial主机

[ESP32]:基于esp-modbus实现serial主机

LINKKEEE的博客 2567

【5G】5G 核心网(5GC)基本架构

本文旨在科普5G核心网相关知识...

Learning makes me happy (0^◇^0) 4万+

浅谈 AC 自动机

省流:比后缀数组还要简单的 AC 自动机!!

WerChange的OI博客 2893

Latex参考文献中大写字母编译后自动变成了小写,如何保持原字母大写形式

bib文件参考文献中大写自动变为小写,如何保持原大写问题。Latex: 保持参考文献大小写,overleaf文献编译后,原大写字母自动变成了小写字母,如何保持原字母大写

我的个人博客 5805

AC自动机-详解AC自动机以及模板

AC自动机-详解AC自动机以及模板AC自动机算法简介AC自动机算法大致流程AC自动机详细图解AC自动机模板题与模板题目内容代码详解完整代码 AC自动机算法简介 首先简要介绍一下AC自动机,英文名:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模板匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。 要搞懂AC自动机,先要有字典树Trie和KMP模式匹配算法的基础知识。其中,KMP是用于一对一的字符串匹

qq_43381135的博客 6856

深入解析西门子S7通信协议:从抓包到实战应用

本文深入解析西门子S7通信协议,从环境搭建、抓包分析到实战应用,提供了一套完整的协议分析方法。通过Wireshark工具进行抓包分析,详细拆解了S7协议各层结构,并结合真实案例,展示了如何利用抓包技术解决通信故障、优化性能及进行安全审计,是掌握工业通信底层原理的实用指南。

weixin_29224529的博客 281

Seurat 单细胞转录组测序数据分析教程(三)——python(scanpy)

文章参考至,做了一个更详细的解读。本教程探讨了 scanpy 的可视化可能性,分为三个部分:嵌入的散点图(例如 UMAP、t-SNE)使用已知标记基因鉴定簇差异表达基因的可视化在本教程中,我们将使用来自 10x 的数据集,其中包含来自PBMC的 68k 个细胞。Scanpy 在其分布中包括该数据集的简化样本,该数据集仅包含 700 个细胞和 765 个高度可变的基因。该数据集已经过预处理和 UMAP 计算。在本教程中,我们还将使用以下文献标记:B细胞:CD79A、MS4A1。

coffeeii的博客 5828

AC自动机(详解)

需要提前了解的知识:KMP, 字典树 例题:传送门 AC自动机是KMP和字典树的结合体, 如果说KMP用于单模式匹配,那么AC自动机是用于多模式匹配的。 举个例子,KMP适用于在一篇文章中找一句话, AC自动机适合在一篇文章中寻找多句话(并不是简单的多用几次KMP)。 KMP算法构建了一个查询表(nex数组), 我们可以按照相同的思路构建nex表,在ac自动机中成为失配数组。 算法思路: 先将所有的模式串建立字典树, 建立nex数组,然后就开始匹配。 ...

三季人的博客 1万+

ifix5.8连接ab plc的点-通过rslinx

以ifix连接ab plc的点为例 1.先在rslinx上把plc的点导出为opc server 2.使用opc power tool 作为opc client 去连接 3.保存到项目的PDB文件夹下面,并且以节点名命名。 也可以不以节点名命名,系统自动会生成一个以节点名命名的这种文件,就显得很乱。 同时,项目的PDB目录下面必须还得拷过来一个de...

中国智造2025 4110

AC自动机步骤详解

AC自动机 算法意义: 求多个字符串是否在主串中出现过。可依据情况分别求出出现次数,出现位置等。 学习基础: 要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。 AC自动机的构造: 1.构造一棵Trie,作为AC自动机的搜索数据结构。 2.构造fail指针,使当前字符失配时跳转到具有最长公共前后缀的字符继续匹配。如同 KMP算法一样, AC自

问鼎63的博客 2511

IAR调试CC1310的错误:Fatal error:Failed to connect to the XDS emlulator (Error -241 @ 0x0:)

从simplelink_cc13x0_sdk_2_10_00_36导入collector工程后,rebuild后进行debug,出现了如图错误:Fatal error:Failed to connect to the XDS emlulator (connect ICEPick)...(Error -241 @ 0x0)A router subpath could not be accessed....

qq_40417648的博客 6228

YOLOv11的物理信息神经网络(PINN):引入物理规律约束目标运动预测

本文介绍了YOLOv11目标检测与PINN物理信息神经网络的融合技术。YOLOv11采用增强特征提取和参数优化架构,在保持实时性的同时提升检测精度。PINN通过将物理方程嵌入损失函数,实现数据高效学习。两者的结合可显著提升运动预测准确性和遮挡处理鲁棒性。文章详细阐述了环境配置、YOLOv11模型验证方法,并提供了基础PINN框架代码实现,展示了物理约束如何通过自动微分整合到神经网络中。该融合技术适用于自动驾驶、无人机导航等需要物理规律建模的视觉感知场景。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 423

字符串处理【AC自动机】 - 原理 AC自动机详解

字符串处理【AC自动机】 - 原理 AC自动机详解

代码改变世界 3589

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

AC自动机算法详解 (转载)

AC自动机算法详解 (转载) 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。KMP算法是单模式串的字符匹配算法,AC自动机是多模...

llettod的专栏 276

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

AC自动机详解及实现

1.背景 之前的Trie树,DBTrie都属于前缀树,虽然DAT每次状态转移的时间复杂度都是常数,但全切分长度为n的文本时,时间复杂度为O(n2)。这是因为**扫描过程中需要不断的挪动起点,发起新的查询**。所以说,DAT的全切分复杂度为O(n2)。 2.为什么需要AC自动机 显然,前缀树的短板是扫描,查询一个句子时,前缀树需要不断的挪动起点,发起新查询,这个过程浪费了大量时间。 举个栗子,扫描...

huoji555的博客 3032

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

AC自动机入门详解

一.AC自动机的引入. 我们都知道KMP可以用来一个子串与母串之间的匹配,只需要通过一个next指针就可以实现O(n+m)匹配,已经达到了算法下界,是一个很优秀的算法了. 但是我们如何考虑多个子串与母串之间的匹配呢? 如果多个子串与母串之间的匹配用KMP来实现,效率可能就不那么高了,这可怎么办呢?这就是AC自动机的由来. AC自动机是什么?其实就是在Trie树上跑KMP. 二.Trie树与KM...

hzk_cpp的博客 592

AC自动机算法详解

首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。KMP算法是单模式串的字符匹配算法,AC自动机是多模式串的字符匹配算法。 AC自动...

bbbeoy的专栏 209

ac自动机详解

转自大佬的blog:https://www.cnblogs.com/cmmdc/p/7337611.html 简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Tri...

dajiangyou123456的博客 430
上一篇: 树状数组详解(求逆序对)
下一篇: 并查集详解
Wu_while
博客等级 码龄6年 50粉丝 53原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值