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✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
