LeetCode-0324~28
leetCode1032
思路:想的是维护一个后缀数组,然后用Set去判断一下,结果超时了,去看题解,好家伙AC自动机,没办法,开始学。
正确题解:
class ACNode{public ACNode[] children;public boolean exist;public ACNode fail;public ACNode(){this.children = new ACNode[26];this.exist = false;this.fail = null;}public ACNode FindFail(int ch){ACNode tmp = this.fail;while(tmp!=null&&tmp.children[ch]==null)tmp = tmp.fail;return tmp;}
}class Trie{public ACNode root;public Trie(){this.root = new ACNode();}public void insert(String p){ACNode tmp = this.root;for(int i=0;i<p.length();i++){char ch = p.charAt(i);int it = ch - 'a';ACNode child = tmp.children[it];if(child==null){child = new ACNode();tmp.children[it] = child;}tmp = tmp.children[it];}tmp.exist = true;}
}class StreamChecker {private Trie root;private ACNode current;public StreamChecker(String[] words) {this.root = new Trie();this.current = this.root.root;for(int i=0;i<words.length;i++){this.root.insert(words[i]);}Queue<ACNode> queue = new LinkedList<>();for(int i=0;i<26;i++){ACNode child = this.current.children[i];if(child!=null){child.fail = this.current;queue.offer(child);}}// BFSwhile(!queue.isEmpty()){ACNode tmp = queue.poll();for(int i=0;i<26;i++){ACNode child = tmp.children[i];if(child!=null){ACNode fail = tmp.FindFail(i);if(fail!=null){child.fail = fail.children[i];child.exist = fail.children[i].exist||child.exist;}else{child.fail = this.current;}queue.offer(child);}}}}public boolean query(char letter) {ACNode tmp = this.current;int it = letter - 'a';while(tmp.fail!=null&&tmp.children[it]==null)tmp = tmp.fail;if(tmp.children[it]!=null){this.current = tmp.children[it];}else{this.current = this.root.root;}if(this.current.exist){return true;}else {return false;}}
}
之前代码也记录一下吧,虽然过不了
class StreamChecker {private Set<String>wordset;private String postfix[];public StreamChecker(String[] words) {this.wordset = new HashSet<String>();this.postfix = new String[]{};for(int i=0;i<words.length;i++){this.wordset.add(words[i]);}}public boolean query(char letter) {int len = this.postfix.length;String newPostfix[] = new String[len+1];boolean flag = false;if(len==0)newPostfix[0]=""+letter;else {for(int i=0;i<len;i++)newPostfix[i]=this.postfix[i]+letter;newPostfix[len]=""+letter;}this.postfix=newPostfix;for(int i=0;i<this.postfix.length;i++){if(this.wordset.contains(this.postfix[i])){flag = true;break;}}return flag;}
}/*** Your StreamChecker object will be instantiated and called as such:* StreamChecker obj = new StreamChecker(words);* boolean param_1 = obj.query(letter);*/
AC自动机
与KMP同时期算法,用于多模式匹配
同样给你一个T串,你要搜索多个单词(p串),如果是KMP的话,有几个单词就搜几遍,AC自动机进过预处理之后,只要扫描一遍T串就可以把p串里面的单词都找出来。
字典树:
- root节点最大有26个孩子,字母a-z
- 图中有两个圈的点代表单词真正的结尾
- 查找失败:
- 查找字母时发现是空指针
- 找到了单词,但是发现没有这个标记,不是一个单词
fail指针
- 如果i的fail指针是j,则word[j]是word[i]的最长后缀。
- 例如9指向4 则说明he是she的最长后缀。
- 再例如,10指向3 ,hers的最长后缀是ers但是字典树里面并没有,所以只能指向s。
- 如果fail指针指向root,则说明该单词没有后缀在该字典里面
- 利用fail指针查询,一个一个字母进行查询:
- 字母a:root查询失败,回到root
- 字母h:查询到,一直到his整个单词都可以查到。
- 第二个字母h:匹配失败,会跳转到失败指针所指:3好点。多模匹配就是利用单词共同的部分去查找,如果是KMP的话,他会从头再去找hshe,但是利用单词之间共同的后缀部分,可以跳过部分匹配工作。这样一直到节点九,查找到了单词she。并且再进行匹配为空,顺着fail指针到4号。
- 字母e找到了he单词,然后顺着找又找到了hers。
- 为什么顺着fail指针移动可以多模匹配:利用了单词的后缀可能是其他单词的前缀的关系
- 不仅要检测是否存在,还需要检测存在的位置
预处理过程(fail指针+exist单词信息)
- 根据p串里面的单词构建字典树
- 例如1->2->3构建出完整的单词,在该节点存储一个数组,存储以次字母结尾的单词长度。
- 实现fail指针:使用bfs层序遍历
- 对于单个字母,前后缀为空,直接指向root;字典树第一次的fail指针都会指向root
- 对于深度大于1的节点,他的fail指针需要用到父节点的失败指针,他会观察父fail指针有没有和他字母一样的孩子。如果为空,也会指向root,否则,会指向对应节点。
- 如果一个单词的结尾节点的fail指针指向了另一个单词的结尾节点,则该单词的结尾数组里面会追加一个单词长度信息。
查找T串
- 查a:从root出发,root没有此儿子,空串,还是在root不动。
- 查h:从root出发,root有h,但是里面exist信息为空,虽然是节点单不是p串单词,继续从h出发匹配
- 查i:从h出发,h有儿子i,同样exist为空,继续
- 查s:从i出发,i有s儿子,且有exist信息,此时T串迭代器it为3,p串长度为3,回退3个就是1-3是p串单词his。继续匹配,从10号节点s出发
- 查h:从s出发,s没有h这个儿子,走fali指针到4号匹配。4号有h儿子,到达5号节点,exist为空,继续查。
- 查e:从h(5号)出发,h有e这个儿子,且exist有货,同时找到了she和he两个单词。继续查
- 查r:e没有r,走fail指针到3号,3号e确实有r儿子,exist为空,继续查
- 查s:r有s,且exist有货,找到hers单词
代码实现
字典树
这里要求会写BFS和字典树,字典树的实现写了一下:
// 仅匹配小写字母,如果想广泛匹配,可以修改children数组
class TrieNode{private TrieNode[] children;private boolean isEndOfWord;public TrieNode(){this.children = new TrieNode[26];this.isEndOfWord = false;}public TrieNode[] getChildren(){return this.children;}public boolean isEndOfWord(){return this.isEndOfWord;}public void setEndOfWord(boolean endOfWord){this.isEndOfWord=endOfWord;}
}public class Trie {private TrieNode root;public Trie(){root = new TrieNode();}public void insert(String word){TrieNode current = this.root;for(int i=0;i<word.length();i++){char ch = word.charAt(i);TrieNode child = current.getChildren()[ch-'a'];if(child==null){child = new TrieNode();current.getChildren()[ch-'a'] = child;}current = child;}current.setEndOfWord(true);}public boolean search(String word){TrieNode current = this.root;for(int i=0;i<word.length();i++){char ch = word.charAt(i);TrieNode child = current.getChildren()[ch-'a'];if(child==null){return false;}current = child;}return current.isEndOfWord();}
}
AC自动机
class ACNode {public ACNode[] children;List<Integer> exist;public ACNode fail;public ACNode(){this.children = new ACNode[26];this.exist = new ArrayList<>();this.fail = null;}/*** 如果i.fail指向j,则j是i的最长后缀,如果此时j是一个单次的话,就要将j的exist也转存的i的exist中*/public void AddExist(List<Integer> exist){if(exist==null||exist.size()==0)return;for(int i=0;i<exist.size();i++){this.exist.add(exist.get(i));}}/*** 迭代寻找失败指针,只有当找到时或者*/public ACNode FindFail(int c){ACNode tmp = this.fail;while (tmp!=null&&tmp.children[c]==null){tmp = tmp.fail;}return tmp;}
}class TrieTree{public ACNode root;public TrieTree(){this.root = new ACNode();}public void insert(String p){ACNode current = this.root;for(int i=0;i<p.length();i++){char ch = p.charAt(i);int it = ch-'a';ACNode child = current.children[it];if(child==null){child = new ACNode();current.children[it] = child;}current = current.children[it];}current.exist.add(p.length());}
}public class AC_automaton {private TrieTree root;public AC_automaton(){this.root = new TrieTree();}/*** 构建字典树,并且生成fail指针*/public void build(String p[]){for(int i=0;i<p.length;i++){this.root.insert(p[i]);}// 开始补全fail指针Queue<ACNode> queue = new LinkedList<>();// 处理第一层ACNode root = this.root.root;for(int i=0;i<26;i++){if(root.children[i]!=null){root.children[i].fail=root;queue.offer(root.children[i]);}}// BFSwhile (!queue.isEmpty()){ACNode current = queue.poll();for(int i=0;i<26;i++){ACNode child = current.children[i];if(child!=null){queue.offer(child);// 调用迭代查找ACNode fail = current.FindFail(i);if(fail==null){child.fail=root;}else {child.fail=fail.children[i];// 将最长后缀的exist数组继承过来child.AddExist(fail.children[i].exist);}}}}}/*** 匹配T串*/public void query(String T){if(T==null||T.length()==0)return;ACNode current = this.root.root;for(int i=0;i<T.length();i++){char ch = T.charAt(i);int it = ch-'a';while (current.fail!=null&¤t.children[it]==null){current=current.fail;}if(current.children[it]!=null){current = current.children[it];}else{continue;}if(current.exist.size()>0){for(int j=0;j<current.exist.size();j++){int l = current.exist.get(j);if(i-l+1<0){System.out.print("Error: i-l<0!");continue;}String str = T.substring(i-l+1,i+1);System.out.println("找到字符串:"+str);}}}}
}
测试:
public class MyTest {@Testpublic void TestTrieInsert(){Trie root = new Trie();root.insert("trie");System.out.print(root);}@Testpublic void TestAC_automaton(){AC_automaton acAutomaton = new AC_automaton();acAutomaton.build(new String[]{"he","hers","his","she"});acAutomaton.query("ahishers");}}
结果:
找到字符串:his
找到字符串:she
找到字符串:he
找到字符串:hers
相关文章:
LeetCode-0324~28
leetCode1032 思路:想的是维护一个后缀数组,然后用Set去判断一下,结果超时了,去看题解,好家伙AC自动机,没办法,开始学。 正确题解: class ACNode{public ACNode[] children;publi…...
Vue2自己封装的基础组件库或基于Element-ui再次封装的基础组件库,如何发布到npm并使用(支持全局或按需引入使用),超详细
最终效果如下 一、先创建vue2项目 1、 可以用vue-cli自己来创建;也可以直接使用我开源常规的vue2后台管理系统模板 以下我以 wocwin-admin-vue2 项目为例 修改目录结构,最终如下 2、修改vue.config.js文件 module.exports { // 修改 src 目录 为 exam…...
【开发】中间件——MongoDB
MongoDB是一个基于分布式(海量数据存储)文件存储的数据库。 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json…...
C++进阶 — 【C++11】
目录 一、 C11简介 二、 统一的列表初始化 1.{}初始化 2. initializer_list 三、声明 1. auto 2. decltype 3. nullptr 四、范围for循环 五、STL中一些变化 1. 提供了一些新容器 2.容器中增加了一些新方法 六、右值引用和移动语义 1. 左值引用和右…...
Mac安装Homebrew
1.前往Homebrew官网,复制官网的安装命令 https://brew.sh/ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装结束后,记得仔细看脚本执行最后的提示,需要我们复制两行命令执…...
【详细】利用VS2019创建Web项目,并发送到IIS,以及IIS与ASP.NET配置
一、打开VS2019选择创建新项目【最好以管理员身份运行VS2019,后面发布网站时需要以管理员身份,避免后面还要重启,可以一开始就以管理员身份运行】 二、选择语言为C#,然后选择“ASP.NET Web应用程序(.NET Framework&…...
FasterRcnn,Yolov2,Yolov3中的Label Assignment机制 和 ATSS
一般把anchor到gt之间如何匹配的方法称为label assignment,也就是给预设的anchor打上正负样本等标签,方便我们后续进一步回归。 其实RPN和Yolo有各自的label assignment方法, 在Faster rcnn,yolo,RetinaNet中…...
使用Java技术WebSocket创建聊天、群聊,实现好友列表,添加好友,好友分组,聊天记录查询功能。
文章目录 引入依赖主要代码配置WebSocket创建通讯完整后台项目代码下载WebSocket的由来: 之前只有一个http协议,http协议是请求响应,存在缺陷,就是请求只能由客户端发起,然后请求到服务器,服务器做响应,但是如果服务器状态做了改变,客户端并不能即使的更新,之前的是按照…...
【Redis07】Redis基础:Bitmap 与 HyperLogLog 相关操作
Redis基础学习:Bitmap 与 HyperLogLog 相关操作继续进行 Redis 基础部分的学习,今天我们学习的是两种另外的数据类型。说是数据类型,但其实它们实际上使用的都是 String 类型做为底层基础,只不过是在存储的时候进行了一些特殊的操…...
华为路由器 VRRP主备配置
组网需求 如下图所示,PC1通过SW1双归属到R1和R2。为保证用户的各种业务在网络传输中不中断,需在R1和R2上配置VRRP主备备份功能。 正常情况下,主机以R1为默认网关接入Internet,当R1故障时,R2接替R1作为网关继续进行工作…...
docker容器安装ES
1.拉取镜像 docker pull elasticsearch:6.5.42.修改别名 docker tag [容器ID] es65:6.5.42.启动应用 docker run -it -d -p 9200:9200 -p 9300:9300 --name es -e ES_JAVA_OPTS"-Xms128m -Xmx128m" es65:6.5.43.拷贝配置文件到宿主机 docker cp es:/usr/share/ela…...
Python Module — prompt_toolkit CLI 库
目录 文章目录目录prompt_toolkit示例化历史记录热键自动补全多行输入Python 代码高亮自定义样式prompt_toolkit prompt_toolkit 是一个用于构建 CLI 应用程序的 Python 库,可以让我们轻松地构建强大的交互式命令行应用程序。 自动补全:当用户输入命令…...
springboot mybatis-plus 调用 sqlserver 的 存储过程 返回值问题
问题: 在使用 mybatis-plus 调用sqlserver 存储过程 没有返回值 经过资料查找 注意点 此处使用Map传参,原因在于存储过程的返回值,通常在参数定义中实现,如In 入参、out 出参。 这样当执行后有结果返回时,则可以将结…...
【0180】PG内核读取pg_hba.conf并创建HbaLine记录(1)
文章目录 1. pg_hba.conf文件是什么?2. postmaster何时读取pg_hba.conf?2.1 pg内核使用pg_hba.conf完成客户端认证的原理2.2 读取pg_hba.conf的几个模块3. pg内核读取pg_hba.conf过程3.1 VFD机制获取文件描述符3.2 根据fd读取文件内容相关阅读: 【0178】DBeaver、pgAdmin I…...
【原型设计工具】上海道宁为您提供Justinmind,助力您在几分钟内形成原型,并现场测试,无需编写任何代码
Justinmind是用于 Web和应用程序的原型制作工具 在几分钟内形成原型 并在现场进行测试 无需编写任何代码 单击一下即可轻松在线获取您的设计 并与整个团队共享 享受高效的沟通和快速反馈 以实现持续改进和利益相关者的支持 开发商介绍 JustinMind是由西班牙JustinMind公…...
计算机网络中---HDLP协议和PPP协议
目录 HDLC协议PPP协议HDLC协议和PPP协议HDLC协议 HDLC协议【高级数据链路控制协议】是一种数据链路层协议,用于在两个节点之间传输数据。以下是HDLC协议的重点知识: HDLC协议定义了一种标准的帧格式,包括起始标志、地址字段、控制字段、信息字段、校验字段和结束标志。HDLC…...
k8s之节点kubelet预留资源配置
k8s之kubelet预留资源配置1 前言2 预留资源Kube-reservedSystem-reservedEviction Thresholds实施节点可分配约束3 Pod优先级4 生产应用配置文件重启kubelet服务查看节点资源1 前言 最近k8s在使用过程中遇到这样一个问题 由于Pod没有对内存及CPU进行限制,导致Pod在…...
机器学习笔记之前馈神经网络(四)反向传播算法[数学推导过程]
机器学习笔记之前馈神经网络——反向传播算法[数学推导过程]引言回顾:感知机算法非线性问题与多层感知机反向传播算法(BackPropagation,BP\text{BackPropagation,BP}BackPropagation,BP)场景构建求解各权重更新量图示描述反向传播过程总结引言 上一节介绍了M-P\tex…...
vscode+elementui校园跑腿系统 nodejs+vue
本系统从用户的角度出发,结合当前的校园环境而开发的,在开发语言上是使用的Java语言,在框架上我们是使用的Vue框架,数据库方面使用的是MySQL数据库,开发工具为IDEA。 基于Vue的校园跑腿管理系统中的管理员配送用户都可…...
[蓝桥杯单片机8]定时器的简单应用
1、本实验内容 利用51单片机的定时/计数器T0的模式1实现间隔定时,每隔1秒L1指示灯闪烁一下,也就是点亮0.5秒,熄灭0.5秒;每隔2秒L8指示灯闪烁一下,即点亮1秒,熄灭1秒。2、基础知识 定时/计数器,是…...
node-HTTP协议
文章目录一. 概念二. 请求报文的组成三.HTTP请求行四.HTTP请求头五.HTTP的请求体六.响应报文的组成七.创建HTTP服务八.获取HTTP请求报文九.HTTP设置响应十.GET和POST请求的区别一. 概念 HTTP协议. 中文叫超文本传输协议; 是一种基于TCP/IP的应用层通信协议; 这个协议详细规定了…...
基于springboot+vue的地方美食分享网站
081-springboot基于vue的地方美食分享网站开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包&am…...
【Android】之【Aplication】
一、Application简介 Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息。 Android系统自动会为每个程序运行时创建一个Application类的对象且只创建…...
社区之声|Grant Program支持Moonbeam生态壮大
在本次社区之声会议中,Moonbeam基金会解释生态系统Grant流程、一个由社区成员组成的圆桌讨论表达各自对此次Grant的看法,Moonbeam开发者关系工程师演示了如何在Snapshot对申请生态系统Grant项目的投票。观看视频回顾 请注意,内容仅供参考&am…...
GO实现Redis:GO实现Redis协议解析器(2)
本文实现Redis的协议层,协议层负责解析指令,然后将指令交给核心database执行echo database用来测试协议层的代码https://github.com/csgopher/go-redis RESP协议 RESP是客户端与服务端通信的协议,格式有五种:正常回复࿱…...
Geoserver 发布wmts服务,以及cesium加载发布的wmts服务
WMTS提供了一种采用预定义图块方法发布数字地图服务的标准化解决方案。WMTS弥补了WMS不能提供分块地图的不足。WMS针对提供可定制地图的服务,是一个动态数据或用户定制地图(需结合SLD标准)的理想解决办法。WMTS牺牲了提供定制地图的灵活性&am…...
【微信小程序】selectComponent(#id)失败得到是null分析
小程序中无法像网页中轻易的获取DOM元素,需要依靠 this.selectComponent(#id)this.selectAllComponents(#id) 本文主要针对 this.selectComponent 获取DOM元素失败的原因 下面开始正文 上图为我的业务代码,由图可知,通过for循环遍历渲染ca…...
JVM中引用计数法与可达性分析
目录 概要 如何判断对象已死? 引用计数算法 优点 缺点 举例说明 可达性分析 图例说明 GC Roots的对象包括以下几种 可达性分析回收过程 四大引用 回收方法区 方法区的垃圾收集主要回收两部分内容: 1. 废弃的常量 2. 不再使用的类型。 JVM是…...
JS-对象篇
内容 简单介绍 重点介绍三个 Array,String和JSON 后面这两个不是重点 BOM-浏览器对象模型 DOM-文档对象模式(JS中每个HTML标签都封装成一个DOM对象) Array 和java不同 方式一 JS中是var 变量 new Array()(这个变量名后面没有[]这个标记&…...
【Unity】创建一个自己的AR安卓程序
目录1 环境配置2 下载官方提供的AR Starter工程3 AR Starter工程中的包以及打包设置3.1 Package Manager3.2 Player Settings4 创建一个新的AR场景5 AR场景中的物体6 在unity中运行AR场景7 在AR场景的基础上添加自己的想法7.1 修改Cube的旋转速度/方向7.2 将Cube替换为其他物体…...
有限公司属于什么企业类型/中山口碑seo推广
上一篇中已经讲到了如何安装单击版Redis,这一篇我们来说下如何安装Cluster,关于哨兵模式这里我就不写文章安装了,有兴趣的同学可以自己去研究,哨兵模式可以在主从模式下在创建三台机器的哨兵集群监控redis主从集群即可。 本文由于…...
家装平面设计主要做什么/福州网站seo公司
音视频实践学习 android全平台编译ffmpeg以及x264与fdk-aac实践ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器android全平台编译ffmpeg合并为单个库实践android-studio使用cmake编译ffmpeg实践android全平台下基于ffmpeg解码MP4视频文件为YUV文件android全平台编译…...
做网站多少钱google/搜索引擎推广方案
在vue中methods互相调用的方法 转载于:https://www.cnblogs.com/macT/p/10212878.html...
wordpress 维基主题/西安seo服务培训
美团团购订单系统优化记团购订单系统简介 美团团购订单系统主要作用是支撑美团的团购业务,为上亿美团用户购买、消费提供服务保障。2015年初时,日订单量约400万~500万,同年七夕订单量达到800万。 目标 作为线上S级服务,稳定性的提…...
高端企业网站价位/百度指数查询入口
作者:天琼,「数据游戏」优胜队伍成员 介绍 本文整理记录了参与的一次小型数据分析竞赛「数据游戏」,竞赛目标是预测2019年5月15日A股闭市时招商银行600036的股价。 主要思路是利用ARIMA算法做时间序列预测。 使用的数据是公开的数据集 tushar…...
免费外贸网站模板下载/正规网站优化推广
linux内核是一个整体是结构。因此向内核添加任何东西。或者删除某些功能 ,都十分困难。为了解决这个问题。引入了内核机制。从而可以动态的想内核中添加或者删除模块。模块不被编译在内核中,因而控制了内核的大小。然而模块一旦被插入内核,他就和内核其他部分一样。这样一来 就…...