Aho Corasick Algorithm
文章目录
- 前言
- 介绍
- 实现
- 参考
前言
Aho Corasick Algorithm
又叫AC自动机
,该算法是一个匹配算法,用来匹配文本Text
中多个patterns
分别出现的次数;
我们定义n
为patterns
的总长度;m
为Text
的长度;
问题:在ahishershe
文本中找出以下"he", "she", "hers", "his"
各个patterns
出现的次数;
最直接的暴力解法时间时间复杂度为O(n*m)
,如果采用KMP Algorithm
,会把时间度降低为O(n+m)
,但是这是在单一的pattern
的情况下,在k个pattern
的情况下,应该成倍的增长m
,时间复杂度为O(n+k*m)
,使用Aho Corasick Algorithm
可以把时间优化为O(n+m+z)
,其中z表示出现的次数;
介绍
AC
自动机利用的前缀树Trie
这一数据结构;前缀树是一种很简单的结构,其构造如下:

我们可以构建Trie
然后使用窗口进行暴力搜索,其时间复杂度为O(m*max(L))
,这里面的max(L)
是Trie
的深度;
这里面可以优化的一个点是,我们可以利用不匹配词的最长后缀作为词的前缀去优化查找,而不是不匹配就重新从root
开始;找到最长的公共后缀将保证我们不需要再次检查那么多字符串,并且在每次不匹配之后我们都会重复上一步骤;
如图所示:

这些指向最长后缀的节点的链接被称为suffix links
或failure links
,在匹配不成功的时候,若有最长的后缀节点,指向最长的后最节点,若没有则指向root
进行重新查找;
假设在一颗Trie
上有字符串w,x,...
,其中x
是w
的最长的后缀,所以有红线连接w
和a
,若存在wa
和xa
,这xa
也是wa
的最长后缀,也用红线连接;

若xa
不存在,就去找除了x
以外的和w
的最大公共后缀,如果发现y
符合条件,可以对y
进行匹配;如果y
不符合条件,就接着找除了x,y
以外的和w
的最大公共后缀,依次进行;

其次需要优化的一点输出环节,如果pattern1
是pattern2
的后缀的情况下,我们可能会忽略掉pattern1
,所以在寻找最大后缀时需要进行判断,如果最大后缀结点是pattern
,就用output link
连接原结点指向该结点,在以该结点为原结点去连接,直到root
;如果不是就判断该结点的最大后缀结点是否是pattern
,再用原结点去连接这一个结点;

在文本sting
中,遍历到i
的时候,可以发现sti
的最大后缀ti
并不是pattern
,于是就找ti
的最大后缀i
,是pattern
,于是用蓝色的线把sti
和i
结合起来;这里加粗了这一过程;
在遍历到n
的时候,发现tin
和in
都是pattern
,依次进行连接

这时时间复杂度为O(m+z)
,其中z
表示pattern
的出现次数;
实现
下面是python实现的代码:
from collections import defaultdictclass ahocorasick:def __init__(self, words):self.max_states = sum([len(word) for word in words])self.max_characters = 26self.out = [0] * (self.max_states + 1)self.fail = [-1] * (self.max_states + 1)self.goto = [[-1] * self.max_characters for _ in range(self.max_states + 1)]for i in range(len(words)):words[i] = words[i].lower()self.words = wordsself.states_count = self.__build_matching_machine()def __build_matching_machine(self):k = len(self.words)states = 1for i in range(k):word = self.words[i]current_state = 0for character in word:ch = ord(character) - 97if self.goto[current_state][ch] == -1:self.goto[current_state][ch] = statesstates += 1current_state = self.goto[current_state][ch]self.out[current_state] |= (1 << i)for ch in range(self.max_characters):if self.goto[0][ch] == -1:self.goto[0][ch] = 0queue = []for ch in range(self.max_characters):if self.goto[0][ch] != 0:self.fail[self.goto[0][ch]] = 0queue.append(self.goto[0][ch])while queue:state = queue.pop(0)for ch in range(self.max_characters):if self.goto[state][ch] != -1:failure = self.fail[state]while self.goto[failure][ch] == -1:failure = self.fail[failure]failure = self.goto[failure][ch]self.fail[self.goto[state][ch]] = failureself.out[self.goto[state][ch]] |= self.out[failure]queue.append(self.goto[state][ch])return statesdef __find_next_state(self, current_state, next_input):answer = current_statech = ord(next_input) - 97while self.goto[answer][ch] == -1:answer = self.fail[answer]return self.goto[answer][ch]def search_words(self, text):text = text.lower()current_state = 0result = defaultdict(list)for i in range(len(text)):current_state = self.__find_next_state(current_state, text[i])if self.out[current_state] == 0: continuefor j in range(len(self.words)):if (self.out[current_state] & (1 << j)) > 0:word = self.words[j]result[word].append(i - len(word) + 1)return resultif __name__ == "__main__":words = ["he", "she", "hers", "his"]text = "ahishershe"aho_chorasick = ahocorasick(words)result = aho_chorasick.search_words(text)for word in result:for i in result[word]:print("Word", word, "appears from", i, "to", i + len(word) - 1)
参考
Aho Corasick Algorithm (opengenus.org)
相关文章:

Aho Corasick Algorithm
文章目录 前言介绍实现参考 前言 Aho Corasick Algorithm又叫AC自动机,该算法是一个匹配算法,用来匹配文本Text中多个patterns分别出现的次数; 我们定义n为patterns的总长度;m为Text的长度; 问题:在ahis…...
用户管理 --汇总
一、第一节课 1.1 本人写的 前端: 鱼皮 --> 用户中心 第1节课-CSDN博客 中期: 一、用户管理 第1节课中间-CSDN博客 后端: 一、用户管理-CSDN博客 其他的链接 亿图脑图MindMaster 1.2 优秀球友,推荐 Docs 另…...

Flutter视频播放器在iOS端和Android端都能实现全屏播放
Flutter开发过程中,对于视频播放的三方组件有很多,在Android端适配都挺好,但是在适配iPhone手机的时候,如果设置了UIInterfaceOrientationLandscapeLeft和UIInterfaceOrientationLandscapeRight都为false的情况下,无法…...
面试遇到的一些问题(二)
1、v-if v-show 区别,他们的生命周期区别 v-show: (类似于display:none/black 的切换)不管初始值是true 或false 都会进行渲染,状态改变也不会销毁和重新生成。不会影响生命周期 v-if : 是根据条件,dom进行删除插入操作。 依附于普通元素时:会触发父组件的beforeUpdate和u…...

JDK8新特性:Lambda表达式规则及用法,方法引用
目录 Lambda表达式是JDK8新增的一种语法格式 1.作用 2.用法规则: 3.方法引用 Lambda表达式是JDK8新增的一种语法格式 1.作用 简化匿名内部类的代码写法 Lambad用法前提:只能简化函数式接口(一般加有Funcationallnterface)&a…...

【GIS】JDK版本升级到17后,GeoServer的图层无法通过openLayer预览
JDK版本升级到17后,图层无法通过openLayer预览 1. 错误图示 终端输出的错误 网页端无法显示图层,并且输出错误提示 2.原因猜测 估计可能是由于java17的模块化,Java被分成了多个独立部署和运行的模块,这使得Java应用能够更快…...
vue 批量下载文件,不走后端接口的方法
今天ld提了一个需求,说页面的列表里面有要下载的地址,然后点击批量下载。我思索片刻,给出了代码 1.这个是列表页面的代码 <!-- 这个是列表页面的代码 --> <el-table :data"userListShow" align"center"border highlight-…...

科技云报道:AI+PaaS,中国云计算市场迎来新“变量”?
科技云报道原创。 没有小的市场,只有还没有被发现的大生意。 随着企业数字化转型的逐级深入,市场需求进一步向PaaS和SaaS层进发,使之成为公有云服务市场增长的主要动力。 根据IDC最新发布的报告显示,2022-2027五年间中国公有云…...

Windows Service Name重复问题
Windows Service Name重复问题 1,问题 2,打开命令提示符,管理员身份运行 3,输入命令:sc delete MYSQL57 4,验证一下,可以看见已经没有感叹号啦 ,可以看见已经没有感叹号啦...
BBS项目
一.BBS项目介绍 1.项目开发流程 项目立项 ------> 公司高层决定需求调研和分析 ------> 市场人员,技术人员参与 -需求文档说明开发部门开会 ------> 确定项目架构,技术选型,数据库设计UI,UD团队(产品经…...
Java基础——对象类型转换(向上、向下转型)
非继承关系的类之间对象类型不可以互相类型转换,只有继承关系才可以互相转换。 简单说,对象类型转换的前提要是继承关系。 对象类型转换分为:向上转型和向下转型。多态就是一种自动向上转型。 向上转型:子类对象用父类类型接收…...

期末速成数据库极简版【查询】(2)
目录 select数据查询----表 【1】筛选列 【2】where简单查询 【3】top-n/distinct/排序的查询 【4】常用内置函数 常用日期函数 常用的字符串函数 【5】模糊查询 【6】表数据操作——增/删/改 插入 更新 删除 【7】数据汇总 聚合 分类 🙂&#…...

2023年终总结-轻舟已过万重山
自我介绍 高考大省的读书人 白,陇西布衣,流落楚、汉。-与韩荆州书 我来自孔孟故里山东济宁,也许是小学时的某一天,我第一次接触到了电脑,从此对它产生了强烈的兴趣,高中我有一个愿望:成为一名计…...
手机号,邮箱,密码,验证码正则表达式[Java]
Util类: public abstract class RegexPatterns {/*** 手机号正则*/public static final String PHONE_REGEX "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";/*** 邮箱正则*/public static final String EMAIL_REGEX "^[a-zA-Z…...

普冉(PUYA)单片机开发笔记(7): ADC-轮询式多路采样
概述 应用中经常会有使用单片机进行模数转换的需求。PY32F003 具有 1 个 12 位的模拟数字转换器(ADC),今天我们一起来使用一下这个 ADC。 数据手册中对 ADC 简介如下。 SAR ADC:逐次逼近式 ADC,原理参见“参考链接&a…...

uniapp切换页面时报错问题
我们来看如下错误: 该错误的意思是不能切换到 tabbar 页面。tabbar页面通常是公共页面或者底部导航栏,如果我们用 navigateTo 或者 redirectTo 都不能实现页面切换。 我们有两种方式: 第一种是用 switchTab 来进行切换,但注意切…...

Nginx 简单入门操作
前言:之前的文章有些过就不罗嗦了。 Nginx 基础内容 是什么? Nginx 是一个轻量级的 HTTP 服务器,采用事件驱动、异步非阻塞处理方式的服务器,它具有极好的 IO 性能,常用于 HTTP服务器(包含动静分离)、正向代理、反向代理、负载均衡 等等. Nginx 和 Node.js 在很多方…...

ChatGPT是科学还是艺术?
OpenAI最近谈到GPT4变懒的问题,说“它更像是多人共同参与的艺术创作”,那到底大模型是科学还是艺术?...

线程及实现方式
一、线程 线程是一个基本的CPU执行单元,也是程序执行流的最小单位。引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务&#x…...

2023年11月10日 Go生态洞察:十四年Go的成长之路
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...