力扣208题:实现Tire(前缀树)

【题目链接】

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

【解题代码】

public class Trie {public class TireNode {private int level; // 所在层级private boolean end; // 是否为词尾private HashMap<Character, TireNode> nextChs; // 后续所有词节点TireNode(int level, boolean end) {this.level = level;this.end = end;}// 插入下一几点public TireNode putNext(char ch, boolean end) {TireNode newNode = new TireNode(this.level + 1, end);if (this.nextChs == null) this.nextChs = new HashMap<>();this.nextChs.put(ch, newNode);return newNode;}}private TireNode root;public Trie() {// 初始化一个根节点root = new TireNode(-1, false);}public void insert(String word) {TireNode node = match(word);for (int i = node.level + 1; i < word.length(); i++) {node = node.putNext(word.charAt(i), i == word.length() - 1);}// 这个一定要加上,因为插入词的所有字符可能都存在树里,但是作为另外某些词的一部分。node.end = true;}public boolean search(String word) {TireNode node = match(word);// 判断匹配的节点层级是否为词尾,并且此节点为词尾节点。return node.level == word.length() - 1 && node.end == true;}public boolean startsWith(String prefix) {TireNode node = match(prefix);// 判断匹配的节点层级是否为词尾return node.level == prefix.length() - 1;}// 这是插入和查找等函数的关键基础函数,通过词查找最大匹配的节点private TireNode match(String word) {TireNode node = root;char ch;for (int i = 0; i < word.length(); i++) {ch = word.charAt(i);if (node.nextChs != null && node.nextChs.containsKey(ch)) {node = node.nextChs.get(ch);} elsebreak;}return node;}public static void main(String[] args) {Trie trie = new Trie();trie.insert("apple");boolean result = trie.search("apple");   // 返回 TrueSystem.out.println("result = " + result);result = trie.search("app");     // 返回 FalseSystem.out.println("result = " + result);result = trie.startsWith("app"); // 返回 TrueSystem.out.println("result = " + result);trie.insert("app");result = trie.search("app");     // 返回 TrueSystem.out.println("result = " + result);}

【解题步骤】

  1. 设计一个前缀节点类,这个类保存了,当前字符所在层级,是否为某个词的词尾,以及后续所有字符的节点,采用HashMap存储,key是后续字符,value就是下一个节点对象;
    public class TireNode {private int level; // 所在层级private boolean end; // 是否为词尾private HashMap<Character, TireNode> nextChs; // 后续所有词节点TireNode(int level, boolean end) {this.level = level;this.end = end;}// 插入下一几点public TireNode putNext(char ch, boolean end) {TireNode newNode = new TireNode(this.level + 1, end);if (this.nextChs == null) this.nextChs = new HashMap<>();this.nextChs.put(ch, newNode);return newNode;}}
    • 1 字符所在层级level变量的设计:因为词的匹配不光要字符相同,位置也要一样;

    1. 2 是否为某个词的词尾:这个变量也很重要,词尾不一定是叶子节点,因为一个词可能是另一个词的一部分
    • 3 后续所有字符对应的节点变量:采用HashMap存储,肯定是考虑性能因素,查询时间复杂度为O(1)
    1. 4 大家可以看到,这个节点类本身没有存有字符变量,而是放在上一个节点的指向本节点的key中,从减少了重复而不必要的存储;
  2. 设计一个通用的匹配节点查找函数,返回与某个字符串的匹配最深节点:这个匹配函数非常重要,因为无论是插入词,判断字符串 word 在前缀树,是否存在前缀为某个字符串的词,都可以复用这个函数
    // 这是插入和查找等函数的关键基础函数,通过词查找最大匹配的节点
    private TireNode match(String word) {TireNode node = root;char ch;for (int i = 0; i < word.length(); i++) {ch = word.charAt(i);if (node.nextChs != null && node.nextChs.containsKey(ch)) {node = node.nextChs.get(ch);} elsebreak;}return node
    }
  3. 实现Trie() 初始化前缀树对象:因为所有词没有统一的根字符,创建一个虚拟的空的根节点
    // 初始化一个根节点
    root = new TireNode(-1, false);

  4. 编写函数void insert(String word) 向前缀树中插入字符串 word ,首先在前缀树中查找与word最深匹配的节点,然后再将后续字符一一插入树中,最后将词尾字符所在节点的end值设置为true
    public void insert(String word) {TireNode node = match(word);for (int i = node.level + 1; i < word.length(); i++) {node = node.putNext(word.charAt(i), i == word.length() - 1);}// 这个一定要加上,因为插入词的所有字符可能都存在树里,但是作为另外某些词的一部分。node.end = true;
    }
  5. 编写函数boolean search(String word) :首先在前缀树中查找与word最深匹配的节点,最后判断匹配的节点层级是否为词尾,并且此节点为词尾节点。
    public boolean search(String word) {TireNode node = match(word);// 判断匹配的节点层级是否为词尾,并且此节点为词尾节点。return node.level == word.length() - 1 && node.end == true;
    }
  6. 编写函数boolean startsWith(String prefix)  :首先在前缀树中查找与word最深匹配的节点,判断匹配的节点层级是否输入字符串的末尾
    public boolean startsWith(String prefix) {TireNode node = match(prefix);// 判断匹配的节点层级是否为输入字符串的末尾return node.level == prefix.length() - 1;
    }

【思路总结】

  1. 所有树的算法题中,节点类的设计,是必不可少且非常重要,节点中的变量要点到关键并且尽量精简;
  2. 这种算法题目,属于复合应用题,需要借助已有的一些数据结构,比如这里就用到了HashMap;
  3. 前缀树对外提供的功能函数,要根据代码执行逻辑,找到其共性点,设计好内部通用函数,一旦内部通用函数设计好,公共的功能函数只需要在此基础上进行封装即可,达到最大的代码复用,并通过这种“正交性”分解,降解了程序的复杂性

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

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

相关文章

Spring MVC的原理

Spring MVC中的MVC即模型-视图-控制器&#xff0c;该框架围绕一个DispatcherServlet设计而成&#xff0c;DispatcherServlet会把请求分发给各个处理器&#xff0c;并支持可配置的处理器映射和视图渲染等功能。Spring MVC的具体工作流程如下&#xff1a; &#xff08;1&#xff…

微服务不死 — 共享变量在策略引擎项目的落地详解

01 背景 1、共享变量的提出 前段时间&#xff0c;来自亚马逊 Prime Video 团队的一个案例研究在开发者社区中掀起了轩然大波。大体是这样一件事&#xff0c;作为一个流媒体平台&#xff0c;Prime Video每天都会向客户提供成千上万的直播流。为了确保客户无缝接收内容&#xff0…

【动态规划】【数学】【C++算法】805 数组的均值分割

作者推荐 【动态规划】【数学】【C算法】18赛车 本文涉及知识点 动态规划 数学 805 数组的均值分割 给定你一个整数数组 nums 我们要将 nums 数组中的每个元素移动到 A 数组 或者 B 数组中&#xff0c;使得 A 数组和 B 数组不为空&#xff0c;并且 average(A) average(B)…

Java基础(2)

一 String、StringBuffer、StringBuilder String 为什么要设计成不可变的&#xff1f; String是不可变的&#xff08;修改String时&#xff0c;不会在原有的内存地址修改&#xff0c;而是重新指向一个新对象&#xff09;&#xff0c;String用final修饰&#xff0c;不可继承&…

两个bbox的IoU计算步骤分析

IoU&#xff1a;交并比&#xff0c;数值上等于交集面积除以并集面积。 两个bbox的位置关系无外乎以上三种情况&#xff1a;&#xff08;1&#xff09;部分相交。&#xff08;2&#xff09;不相交。&#xff08;3&#xff09;包含。 计算步骤&#xff1a; 计算交集&#xff08…

flutter中使用基于flutter_sound的flutter_sound_record录音

flutter_sound_record 前言文章案例所使用插件的版本号插件安装引入安卓和ios权限支持的编码自定义生成的文件名代码main.dartaudio_player.dart 源码地址 前言 使用flutter_sound,总是出现莫名的错误,所以改为flutter_sound_record,实现录音录制和播放 文章案例所使用插件的…

操作系统-操作系统引导(磁盘 操作系统引导过程)

文章目录 总览一个刚买来的磁盘&#xff08;硬盘&#xff09;往磁盘安装操作系统后操作系统引导过程例&#xff1a;windows操作系统的初始化程序 总览 一个刚买来的磁盘&#xff08;硬盘&#xff09; 此时空空如也 往磁盘安装操作系统后 操作系统在C盘 主引导记录不属于某…

C# 更改Bitmap图像色彩模式

方法一&#xff1a;直接修改RGB的值 首先将BitmapData扫描线上的所有像素复制到字节数组中&#xff0c;然后遍历数组并对每个像素的RGB值进行修改&#xff0c;最后将修改后的像素值复制回BitmapData。这个过程不会影响原始的Bitmap对象&#xff0c;但会改变锁定的位图区域的数…

java idea 中的 Scratches and Consoles

IDEA 中&#xff0c;"Scratches and Consoles" 是一个用于临时代码编辑和交互式开发的工具窗口&#xff0c;作用如下&#xff1a;Scratches&#xff08;草稿&#xff09;&#xff1a;Scratches 是一个用于临时编写和运行代码片段的工具&#xff0c;你可以在其中创建临…

Python实现中英文互译

&#xff1a; 使用预训练模型时经常会涉及到中英文互译&#xff0c;总结一下方法 translate库 安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple translate使用 #中文翻译成英文translator Translator(from_langchinese,to_langenglish)result translator.t…

Python基础第四篇(Python函数)

文章目录 一、函数介绍二、函数的定义三、函数的参数与返回值四、函数说明文档五、函数的嵌套六、变量域七、函数案例1.源代码2.读出结果 在程序设计领域&#xff0c;函数成为一个不可或缺的角色&#xff0c;它们为我们提供了精练、高效和易于管理的编程方式。本篇博客将带您深…

Win32 GetDeviceCaps 函数学习

GetDeviceCaps 函数检索指定设备的设备特定信息。 其第二个参数取不同的值,返回不同结果; void CdevcapView::OnDraw(CDC* pDC) {CdevcapDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// TODO: 在此处为本机数据添加绘制代码CString str1;int ret;ret =…

无人机航迹规划(四):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁殖…

【JavaEE】_网络编程基础

目录 1. 网络编程基础 1.1 网络编程定义 1.2 网络编程中的基本概念 1.2.1 API 1.2.2.发送端和接收端 1.2.3 请求和响应 1.2.4 客户端和服务端 2. Socket 套接字 2.1 概念 2.2 分类 3. UDP数据报套接字编程 3.1 DatagramSocket API 3.1.1 含义 3.1.2 构造方法 3…

【C++记忆站】类和对象(一)

类和对象(一) 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间…

计算机:无所不在的角色与跨学科函数概念的生动探索

The Computer’s Ubiquitous Role and the Conceptual Underpinnings of Functions Across Disciplines: A Vivid Exploration 计算机&#xff1a;无所不在的角色与跨学科函数概念的生动探索 A computer is an extraordinary apparatus that has the remarkable ability to exe…

标准库--容器

1.vector (1). 支持的迭代器类别 为random_access_iterator_tag (2). 内存组织 逻辑上连续的元素&#xff0c;线性地址空间内也连续。 (3). 内存扩张和收缩 a. 初始化时会默认分配一块可容纳指定数量的线性地址空间。 b. 执行reserve(n)&#xff0c;在现有地址空间不足容纳n个元…

初识HarmonyOS

文章目录 本章节目标一、 HarmonyOS简介初识HarmonyOSHarmonyOS系统定位HarmonyOS典型应用场景 二、HarmonyOS架构与安全1. HarmonyOS架构解析内核层系统服务层框架层应用层应用服务智能分发 2. HarmonyOS系统安全正确的人正确的设备正确地使用数据 三、HarmonyOS关键特性1. 硬…

redis远程连接不上解决办法

问题描述&#xff1a; redis远程服务端运行在192.168.3.90计算机上&#xff0c;客户端计算机&#xff08;ip:192.168.3.110&#xff09;通过redsi-cli.exe客户端工具连接时&#xff0c;没有反应&#xff0c;连接不上。 如图所示&#xff1a; 解决步骤&#xff1a; 步骤一&…

OpenCV编译C++测试程序获取cuda设备信息

视频讲解 OpenCV编译C测试程序获取CUDA设备信息 测试代码 test-cv.cpp #include <opencv2/opencv.hpp> #include <opencv2/cudaimgproc.hpp> #include <iostream>using namespace cv; using namespace cv::cuda; using namespace std;int main(int argc, c…