力扣labuladong——一刷day90

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、Trie树实现


前言


Trie 树又叫字典树、前缀树、单词查找树,是一种二叉树衍生出来的高级数据结构,主要应用场景是处理字符串前缀相关的操作

一、Trie树实现

public class TrieMap<V> {//ASCII码个数private static final int R = 256;//当前存在map中的键值对的个数private int size = 0;//Trie 树的根节点private TrieNode<V> root = null;//孩子节点(私有静态类)private static class TrieNode<V>{V val = null;TrieNode<V>[] children = new TrieNode[R];}/*** 从节点node开始搜索key如果存在则返回,不存在返回null(寻找的是节点)* @param node* @param key* @return*/public TrieNode<V> getNode(TrieNode<V>node, String key){TrieNode<V> p = node;for (int i = 0; i < key.length(); i++) {char c = key.charAt(i);if (p == null){return null;}p = p.children[c];}return p;}/*** 获取key值对应的value* @param key* @return*/public V get(String key){TrieNode<V> node = getNode(root,key);if(node != null && node.val != null){return node.val;}return null;}/*** 判断是否存在key* @param key* @return*/public boolean containsKey(String key){return get(key) != null;}/*** 是否存在前缀为predix的键* @param prefix* @return*/public boolean hasKeyWithPrefix(String prefix){return getNode(root,prefix) != null;}/*** 在所有键中寻找query的最短前缀* @param query* @return*/public String shortestPrefixOf(String query){TrieNode<V> p = root;for (int i = 0; i < query.length(); i++) {char c = query.charAt(i);if(p == null){return "";}if(p.val != null){return query.substring(0,i);}p = p.children[c];}if (p != null && p.val != null){return query;}return "";}/*** 在所有键中寻找query最长前缀* @param query* @return*/public String longestPrefixOf(String query){int maxLen = 0;TrieNode<V> p = root;for (int i = 0; i < query.length(); i++) {if(p == null){return "";}char c = query.charAt(i);if(p.val != null){maxLen = i;}p = p.children[c];}if (p != null && p.val != null){return query;}return query.substring(0,maxLen);}/*** 找到所以以prefix为前缀的字符串* @param prefix* @return*/public List<String> keysWithPrefix(String prefix){List<String> res = new LinkedList<>();TrieNode<V> node = getNode(root,prefix);if (node == null){return res;}traverse(node, new StringBuilder(prefix),res);return res;}/*** 遍历以node节点为根的Trie树,找到所有的键* @param node* @param sb* @param res*/private void traverse(TrieNode<V> node, StringBuilder sb, List<String> res) {if (node == null){return;}if (node.val != null){res.add(sb.toString());}for (char i = 0; i < R; i++) {sb.append(i);traverse(node.children[i],sb,res);sb.deleteCharAt(sb.length() -1);}}/*** 匹配模式串pattern得到所有的key* @param pattern* @return*/public List<String> keysWithPattern(String pattern){List<String> res = new LinkedList<>();traverse(root, new StringBuilder(), pattern, 0, res);return res;}/*** 遍历函数,尝试在「以 node 为根的 Trie 树中」匹配 pattern[i..]* @param node* @param path* @param pattern* @param i* @param res*/private void traverse(TrieNode<V> node, StringBuilder path, String pattern, int i, List<String> res) {if (node == null){return;}if (i == path.length()){if (node.val != null){res.add(path.toString());}return;}char ch = pattern.charAt(i);if (ch == '.'){for (char c = 0; c < R; c ++){path.append(c);traverse(node.children[c],path,pattern,i+1,res);path.deleteCharAt(path.length()-1);}}else {path.append(ch);traverse(node.children[ch],path,pattern,i +1,res);path.deleteCharAt(path.length()-1);}}/*** 判断是否存在模式串pattern* @param pattern* @return*/public boolean hasKeyWithPattern(String pattern){return hasKeyWithPattern(root,pattern, 0);}/*** 函数定义:从 node 节点开始匹配 pattern[i..],返回是否成功匹配* @param node* @param pattern* @param i* @return*/private boolean hasKeyWithPattern(TrieNode<V> node, String pattern, int i) {if (node == null){return false;}if (i == pattern.length()){if (node.val != null){return true;}}char ch = pattern.charAt(i);if (ch == '.'){for (char c = 0; c < R; c ++){if (hasKeyWithPattern(node.children[ch],pattern, i +1)){return true;}}}else {return hasKeyWithPattern(node.children[ch],pattern,i+1);}return false;}/*** 在TrieMap中添加或者修改键值对* @param key* @param val*/public void put(String key, V val){if (!containsKey(key)){size ++;}root = put(root, key, val,0);}/***  定义:向以 node 为根的 Trie 树中插入 key[i..],返回插入完成后的根节点* @param node* @param key* @param val* @param i* @return*/private TrieNode<V> put(TrieNode<V> node, String key, V val, int i) {if (node == null){node = new TrieNode<>();}if (i == key.length()){node.val = val;return node;}char c = key.charAt(i);node.children[c] = put(node.children[c],key,val,i+1);return node;}/*** 在 Map 中删除 key* @param key*/public void remove(String key) {if (!containsKey(key)) {return;}// 递归修改数据结构要接收函数的返回值root = remove(root, key, 0);size--;}/*** 定义:在以 node 为根的 Trie 树中删除 key[i..],返回删除后的根节点* @param node* @param key* @param i* @return*/private TrieNode<V> remove(TrieNode<V> node, String key, int i) {if (node == null) {return null;}if (i == key.length()) {// 找到了 key 对应的 TrieNode,删除 valnode.val = null;} else {char c = key.charAt(i);// 递归去子树进行删除node.children[c] = remove(node.children[c], key, i + 1);}// 后序位置,递归路径上的节点可能需要被清理if (node.val != null) {// 如果该 TireNode 存储着 val,不需要被清理return node;}// 检查该 TrieNode 是否还有后缀for (int c = 0; c < R; c++) {if (node.children[c] != null) {// 只要存在一个子节点(后缀树枝),就不需要被清理return node;}}// 既没有存储 val,也没有后缀树枝,则该节点需要被清理return null;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/613711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

strlen/Memcpy_s/strncasecmp

strlen 声明&#xff1a;size_t strlen(const char *str) 举例&#xff1a; #include <stdio.h> #include <string.h>int main () {char str[50];int len;strcpy(str, "This is runoob.com");len strlen(str);printf("|%s| 的长度是 |%d|\n"…

软件测试|使用Pytest、Allure Step和Allure Attach创建详细测试报告

引言 在软件开发过程中&#xff0c;测试是不可或缺的一部分。为了更好地展示测试结果并定位问题&#xff0c;结合Pytest测试框架和Allure测试报告工具可以创建清晰、详细的测试报告。本文将介绍如何使用Pytest、Allure的allure.step()和allure.attach()功能来创建具有丰富信息…

笔记-管理的实践》商业/企业的目的和功能

笔记 From《管理的实践》彼得德鲁克 企业的目的 企业的目的&#xff0c;只有一个正确而有效的定义&#xff1a;“创造顾客”。 市场不是由上帝、大自然或经济力量创造的&#xff0c;而是由企业家创造的。 企业的功能 由于企业的目的是创造顾客&#xff0c;任何企业都有两个基…

springboot 物业管理系统

springboot mysql mybatisthymeleaf 基础信息管理 房屋信息 用户信息 业主信息 租房信息 公告管理 日常管理 财务管理

快速排序-排序算法

算法思想 快速排序采用的仍然是分治的思想。 Step1.每次在无序的序列中选取一个基准数。 Step2.然后将大于和小于基准数的元素分别放置于基准数两边。&#xff08;前面部分的元素均小于或等于基准数&#xff0c;后面部分均大于或等于基准数&#xff09; Step3.然后采用分治法&…

代码随想录——字符串 刷题记录

344.反转字符串 交换&#xff0c;没有难点 541.反转字符串II 注意题干是“每2k”次&#xff0c;所以要有循环 在对剩余的处理中&#xff0c;要先检查每次的剩余数量&#xff0c;包括第一次&#xff0c;所以应该先计算剩余多少决定怎么交换&#xff0c;如果剩余多余2k再进行前…

Docker(网络,网络通信,资源控制,数据管理,CPU优化,端口映射,容器互联)

docker网络 网络实现原理 Docker 网络是指由 Docker 为应用程序创建的虚拟环境的一部分&#xff0c;它允许应用程序从宿主机操作系统的网络环境中独立出来&#xff0c;形成容器自有的网络设备、IP 协议栈、端口套接字、IP 路由表、防火墙等与网络相关的模块。Docker 的网络功能…

预训练中文GPT2(包括重新训练tokenizer)

训练数据 1.json后缀的文件 2.数据是json line格式&#xff0c;一行一条json 3. json结构如下 {"content": "①北京和上海户籍的游客可获得韩国多次签证&#xff1b;②“整容客”可以不经由韩国使领馆、直接在网上申请签证&#xff1b;③中泰免签的实施日期…

C++ 深度优先搜索DFS || 模版题:排列数字

给定一个整数 n &#xff0c;将数字 1∼n 排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 n 。 输出格式 按字典序输出所有排列方案&#xff0c;每个方案占一行。 数据范围 1…

前端页面优化做的工作

1.分析模块占用空间 new (require(webpack-bundle-analyzer).BundleAnalyzerPlugin)() 2.使用谷歌浏览器中的layers&#xff0c;看下有没有影响性能的模块&#xff0c;或者应该销毁没销毁的 3.由于我们页面中含有很大的序列帧动画&#xff0c;所以会导致页面性能低&#xff0…

质量好洗地机有哪些?洗地机口碑榜

在很多人眼中&#xff0c;洗地机可能被简单地视为一种高价的拖把&#xff0c;但作为一个经验丰富的洗地机测评博主&#xff0c;我要强调洗地机在家务工作中的巨大价值。它不仅仅是一种清洁工具&#xff0c;更是集扫地、拖地、洗地以及擦干地板等多项功能于一身的强大设备。通过…

Transformer从菜鸟到新手(六)

引言 上篇文章介绍了如何在多GPU上分布式训练&#xff0c;本文介绍大模型常用的一种推理加速技术——KV缓存。 KV Cache KV缓存(KV Cache)是在大模型推理中常用的一种技巧。我们知道在推理阶段&#xff0c;Transformer也只能像RNN一样逐个进行预测&#xff0c;也称为自回归。…

Android studio 各本版下载

搜索Android studio下载时发现各种需要付费下载的链接&#xff0c;在此记录一下官方的下载地址。 Android Studio 下载文件归档 | Android 开发者 | Android Developers

关于报错 curl: (56) Recv failure: Connection reset by peer

curl ip没问题 curl localhost 则报错 curl: (56) Recv failure: Connection reset by peer 出现这个报错有很多原因, 其中之一就是terminal代理 而关闭代理应用之后, 其实由于配置的终端都是 export指定的代理 所以导致还是一直报错. 通过 curl -v 可以发现 指向了代理ip和…

深入浅出理解SPP、ASPP、DSPP、MDSPP空间金字塔池化系列结构(综合版)

一、参考资料 目标检测&#xff1a;SPP-net SPP原理及实现 金字塔池化系列的理解SPP、ASPP SPP&#xff0c;PPM、ASPP和FPN结构理解和总结 二、空间金字塔池化(SPP) 原始论文&#xff1a;[1] 1. 引言 传统的卷积神经网络中&#xff0c;池化层通常采用固定的池化层级和固定…

使用SpringCache操作Redis缓存数据

SpringCache概念 SpringCache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单的加一个注解&#xff0c;就能实现缓存功能。 SpringCache提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff0c;例如&#xff1a; EHCacheCaffeineRedis 使…

2024 年 1 月安全更新修补了 58 个漏洞(Android )

谷歌发布了针对 Android 平台 58 个漏洞的补丁&#xff0c;并修复了 Pixel 设备中的 3 个安全漏洞&#xff0c;拉开了 2024 年的序幕。 Android 2024 年 1 月更新的第一部分以 2024 年 1 月 1 日安全补丁级别发布在设备上&#xff0c;解决了框架和系统组件中的 10 个安全漏洞&…

学习笔记17——通俗易懂的三次握手四次挥手

提供一种博主本人觉得很好理解的三次握手和四次挥手场景&#xff0c;帮助记忆 三次握手过程 初始状态&#xff1a;客户端处于closed状态&#xff0c;服务器处于listen监听转台客户端向服务器发送一个SYN连接请求&#xff0c;并告诉对方自己此时初始化序列号为x&#xff0c;发送…

TYPE-C接口取电芯片介绍和应用场景

随着科技的发展&#xff0c;USB PDTYPE-C已经成为越来越多设备的充电接口。而在这一领域中&#xff0c;LDR6328Q PD取电芯片作为设备端协议IC芯片&#xff0c;扮演着至关重要的角色。本文将详细介绍LDR6328Q PD取电芯片的工作原理、应用场景以及选型要点。 一、工作原理 LDR63…

【昕宝爸爸小模块】HashMap用在并发场景存在的问题

HashMap用在并发场景存在的问题 一、✅典型解析1.1 ✅JDK 1.8中1.2 ✅JDK 1.7中1.3 ✅如何避免这些问题 二、 ✅HashMap并发场景详解2.1 ✅扩容过程2.2 ✅ 并发现象 三、✅拓展知识仓3.1 ✅1.7为什么要将rehash的节点作为新链表的根节点3.2 ✅1.8是如何解决这个问题的3.3 ✅除了…