每日一道leetcode(新学数据结构版)

news2025/5/20 18:40:46

208. 实现 Trie (前缀树) - 力扣(LeetCode)

题目

Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

提示:

  • 1 <= word.length, prefix.length <= 2000
  • word 和 prefix 仅由小写英文字母组成
  • insertsearch 和 startsWith 调用次数 总计 不超过 3 * 104 次

思路(以下思路是经过检索学习后得出,有一部分的构造方法超出我的知识面了,所以不看的话构造不出来)

  1. 首先这个类本身并没有内置于C++中,需要自己构造。
  2. 这个树的思路比较清楚,是个26叉树,因为其子节点分别都有可能是26个字母(除非存在某个字母不是英文单词的开头,不过显然应该不存在这种情况),然后它还要具有一个功能就是判断到达该节点时是不是组成了一个单词。
  3. 有了这两个基本的点那么就需要构造前缀树的节点类:
    1. 定义一个bool类型变量作为是否是一个单词的判断,再每次插入完成后,对最后一个节点标记为单词位。
    2. 另外需要保存子节点的指针,这里我以为可以直接继续创建对象数组,但是查了一下发现C++仅支持定义自身类型的静态对象或者是对象的指针,所以其实还是对树节点的构造方式不够了解——那么就是构造一个TrieNode* children[26]即可。
    3. 以上都需声明为public类型,否则默认是private的,这样其他类就无法调用。
  4. 接下来是操作逻辑:
    1. 初始化:现在Trie类中定义一个root的TrieNode*节点作为初始节点。
    2. 插入(insert):从根节点和插入单词头开始顺序检查对应位置的单词是否在链中,若在就往下搜,若不在就对该子节点创建一个新的TrieNode对象。不断重复知道单词遍历完成,最后将当前达到的节点的isWord更新为true。
    3. 查找(search):从根节点开始出发,根据待查找单词从头到尾的顺序顺链查找是否已经创建了对应的子节点对象,若是空指针,直接返回false。若遍历完整个单词了,需检查对应的到达节点的isWord是否为true。
    4. 查找前缀(startsWith):和search的方法类似,但最后一步不需要判断isWord,只要能找到这,那么就一定是前缀,直接返回true即可。

代码实现

class TrieNode {
    public:
        bool isWord = false;
        TrieNode* children[26];
};
class Trie {
public:
    TrieNode* root;
    Trie() {
        root = new TrieNode();
    }
    void insert(string word) {
        TrieNode* cur = root;
        char c;
        for(int i = 0; i < word.length(); ++i) {
            c = int(word[i]-'a');
            if(cur->children[c] == nullptr) cur->children[c] = new TrieNode();
            cur = cur->children[c];
        }
        cur->isWord = true;
    }
    
    bool search(string word) {
        TrieNode* cur = root;
        char c;
        for(int i = 0; i < word.length(); ++i) {
            c = int(word[i]-'a');
            if(cur->children[c] == nullptr) return false;
            cur = cur->children[c];
        }
        return cur->isWord;
    }
    
    bool startsWith(string prefix) {
        TrieNode* cur = root;
        char c;
        for(int i = 0; i < prefix.length(); ++i) {
            c = int(prefix[i]-'a');
            if(cur->children[c] == nullptr) return false;
            cur = cur->children[c];
        }
        return true;
    }
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

复杂度分析

  • 时间复杂度:因为直接顺链查找即可,插入、查找、判断前缀的时间复杂度都是O(n)的,初始化的时间复杂度是O(1)的。
  • 空间复杂度:设需要插入的字符串长度之和为L,那么最坏情况的空间复杂度就是26L,若扩展应用范围,如果不是26个字符,而是字符集规模为S,则空间复杂度为O(LS)。

题解

  • 官解的节点的实现是内置的,将Trie类直接当成TrieNode使用,逻辑也是一致的,不过感觉这样写对于类的定义就很模糊,感觉有点dirty,树和节点还是分开定义比较好,不然属性展现的是节点的属性,函数却展现的是树的功能。——虽然代码量少了,但是可读性就差了,感觉不是个好实现。
  • 官解有一个点很可取,判断前缀和查找的功能有很大程度的重合,是可以封装的,确实得锻炼锻炼对这种情况的直觉,避免写出太冗余的代码。
  • 看了其他人的题解发现自己还是太死板了,直接用哈希表貌似很快就能秒了。
    • 首先存一个单词哈希表,然后每次插入定义一个循环存前缀哈希表,时间复杂度是一致的。但是空间复杂度小了,因为很多没出现的节点就不用另外保存了!
    • 还是聪明人多啊!

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

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

相关文章

技术架构缺乏灵活性,如何应对变化需求?

技术架构缺乏灵活性会导致企业在面临市场变化、用户需求演化或新技术出现时难以及时响应&#xff0c;直接影响产品更新速度与竞争力。要有效应对变化需求&#xff0c;需要从引入模块化架构设计、推动微服务拆分、加强架构治理与决策机制、构建中台与平台化能力等方面系统推进。…

【AI时代】Java程序员大模型应用开发详细教程(上)

目录 一、大模型介绍 1. 大模型介绍 1.1 什么是大模型 1.2 技术储备 1.3 大模型的分类 2. 入门案例 3.Token的介绍 二、提示词工程 1. 好玩的提示词案例 1.1 翻译软件 1.2 让Deepseek绘画 1.3 生成数据 1.4 代码生成 2. 提示词介绍 3. Prompt Engineering最佳实…

虚拟网络编辑器

vmnet1 仅主机模式 hostonly 功能&#xff1a;虚拟机只能和宿主机通过vmnet1通信&#xff0c;不可连接其他网络&#xff08;包括互联网&#xff09; vmnet8 地址转换模式 NAT 功能&#xff1a;虚拟机可以和宿主通过vmnet8通信&#xff0c;并且可以连接其他网络&#xff0c;但是…

第31讲 循环缓冲区与命令解析

串口在持续接收数据时容易发生数据黏包&#xff08;先接收的数据尚未被处理&#xff0c;后面的数据已经将内存覆盖&#xff09;的情况&#xff0c;循环缓冲区的本质就是将串口接受到的数据马上拷贝到另外一块内存之中。为了避免新来的数据覆盖掉尚未处理的数据&#xff0c;一方…

数据结构(十)——排序

一、选择排序 1.简单选择排序 基本思想&#xff1a;假设排序表为[1,…,n]&#xff0c;第i趟排序即从[i,…,n]中选择关键字最小的元素与L[i]交换 eg&#xff1a;给定关键字序列{87&#xff0c;45&#xff0c;78&#xff0c;32&#xff0c;17&#xff0c;65&#xff0c;53&…

美蛋工具箱:一站式解决图片、视频、音频和文档处理需求的聚合神器

先放下载链接:夸克网盘下载 宝子们&#xff0c;今天不啰嗦&#xff0c;直接给大家安利一款超好用的聚合工具&#xff0c;有需要的小伙伴赶紧码住&#xff01; 今天要介绍的这款工具叫美蛋工具箱&#xff0c;它是一款聚合类工具。这个软件是绿色版的&#xff0c;聚合了图片工具…

python打卡day16

NumPy 数组基础 因为前天说了shap&#xff0c;这里涉及到数据形状尺寸问题&#xff0c;所以需要在这一节说清楚&#xff0c;后续的神经网络我们将要和他天天打交道。 知识点&#xff1a; numpy数组的创建&#xff1a;简单创建、随机创建、遍历、运算numpy数组的索引&#xff1a…

Redis 学习笔记 5:分布式锁

Redis 学习笔记 5&#xff1a;分布式锁 在前文中学习了如何基于 Redis 创建一个简单的分布式锁。虽然在大多数情况下这个锁已经可以满足需要&#xff0c;但其依然存在以下缺陷&#xff1a; 事实上一般而言&#xff0c;我们可以直接使用 Redisson 提供的分布式锁而非自己创建。…

游戏开发实战(一):Python复刻「崩坏星穹铁道」嗷呜嗷呜事务所---源码级解析该小游戏背后的算法与设计模式【纯原创】

文章目录 奇美拉项目游戏规则奇美拉(Chimeras)档案领队成员 结果展示&#xff1a; 奇美拉项目 由于项目工程较大&#xff0c;并且我打算把我的思考过程和实现过程中踩过的坑都分享一下&#xff0c;因此会分3-4篇博文详细讲解本项目。本文首先介绍下游戏规则并给出奇美拉档案。…

02- 浏览器运行原理

文章目录 1. 网页的解析过程浏览器内核 2. 浏览器渲染流程2.1 解析html2.2 生成css规则2.3 构建render tree2.4 布局(Layout)2.5 绘制(Paint) 3. 回流和重绘3.1 回流reflow&#xff08;1&#xff09;理解&#xff1a;&#xff08;2&#xff09;出现情况 3.2 重绘repaint&#x…

移除链表元素数据结构oj题(力扣题206)

目录 题目描述&#xff1a; 题目解读&#xff08;分析&#xff09; 解决代码 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 题目解读&#xff08;分析&#…

OpenTelemetry 从入门到精通

快速入门 OpenTelemetry 是一个可观测性框架和工具包&#xff0c; 旨在创建和管理遥测数据&#xff0c;如链路、 指标和日志。 重要的是&#xff0c;OpenTelemetry 是供应商和工具无关的&#xff0c;这意味着它可以与各种可观测性后端一起使用&#xff0c; 包括 Jaeger 和 Pro…

【免杀】C2免杀技术(六)进程镂空(傀儡进程)

一、技术定位与核心思想 进程镂空&#xff08;Process Hollowing&#xff09;属于 MITRE ATT&CK 中 T1055.012 子技术&#xff1a;先创建一个合法进程并挂起&#xff0c;随后把其主模块从内存“掏空”并替换为恶意映像&#xff0c;最后恢复线程执行&#xff0c;从而让…

Eclipse Java 开发调优:如何让 Eclipse 运行更快?

Eclipse Java 开发调优&#xff1a;如何让 Eclipse 运行更快&#xff1f; 在 Java 开发领域&#xff0c;Eclipse 是一款被广泛使用的集成开发环境&#xff08;IDE&#xff09;。然而&#xff0c;随着项目的日益庞大和复杂&#xff0c;Eclipse 的运行速度可能会逐渐变慢&#x…

彻底理解事件循环(Event Loop):从单线程到异步世界的桥梁

关于事件循环被问了很多次&#xff0c;也遇到过很多次&#xff0c;一直没有系统整理&#xff0c;网上搜的&#xff0c;基本明白但总感觉不够透彻&#xff0c;最后&#xff0c;自己动手&#xff0c;丰衣足食&#xff0c;哈哈 一、为什么需要事件循环&#xff1f;—— 单线程的困…

Linux(2)——shell原理及Linux中的权限

目录 一、shell的运行原理 二、Linux中权限的问题 1.权限的概念 2.如何进行用户的切换 1&#xff09;从普通用户切到超级用户 2&#xff09;从root用户切到普通用户 3.如何实现提权操作 4.如何将普通用户添加到信用列表&#xff08;sudoers&#xff09; ​编辑5.Lin…

如何在线免费压缩PDF文档?

PDF文件太大&#xff0c;通常是因为内部嵌入字体和图片。怎么才能将文件大小减减肥呢&#xff0c;主要有降低图片清晰度和去除相关字体两个方向来实现文档效果。接下来介绍三个免费压缩PDF实用工具。 &#xff08;一&#xff09;iLoveOFD在线转换工具 iLoveOFD在线转换工具&a…

汽车装配又又又升级,ethernetip转profinet进阶跃迁指南

1. 场景描述&#xff1a;汽车装配线中&#xff0c;使用EtherNet/IP协议的机器人与使用PROFINET协议的PLC进行数据交互。 2. 连接设备&#xff1a;EtherNet/IP机器人控制器&#xff08;如ABB、FANUC&#xff09;与PROFINET PLC&#xff08;如西门子S7-1500&#xff09;。 3. 连…

css:无限滚动波浪线

以上是需要实现的效果&#xff0c;一条无限滚动波浪线&#xff0c;可以用来做区块的分割线。 要形成上下交替的圆形&#xff0c;思路是给div加圆角边框&#xff0c;第一个只有上边框&#xff0c;第二个只有下边框。 循环了100个div&#xff0c;这个数量根据自己容器宽度调整&…

w~自动驾驶~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/13269720 #FastOcc 推理更快、部署友好Occ算法来啦&#xff01; 在自动驾驶系统当中&#xff0c;感知任务是整个自驾系统中至关重要的组成部分。感知任务的主要目标是使自动驾驶车辆能够理解和感知周围的环境元素&…