《剑指 Offer》专项突破版 - 面试题 62 : 详解前缀树以及实现(C++)

目录

一、前缀树的基础知识

二、实现前缀树


 


一、前缀树的基础知识

前缀树,又称为字典树,它用一个树状的数据结构存储一个字典中的所有单词。如果一个字典中包含单词 "can"、"cat"、"come"、"do"、"i"、"in" 和 "inn",那么保存该字典所有单词的前缀树如下图所示。

前缀树是一棵多叉树,一个节点可能有多个子节点。前缀树中除根节点外,每个节点表示字符串中的一个字符,而字符串由前缀树的路径表示。前缀树的根节点不表示任何字符。例如,从上图中前缀树的根节点开始找到字符 'c' 对应的节点,接着经过字符 'a' 对应的节点到达字符 'n' 对应的节点,该路径表示字符串 "can"。

如果两个单词的前缀(即单词最开始的若干字符)相同,那么它们在前缀树中对应的路径的前面的节点是重叠的。例如,"can" 和 "cat" 的前两个字符相同,它们在前缀树对应的两条路径中最开始的 3 个节点(根节点、字符 'c' 和 字符 'a' 对应的节点)重叠,它们共同的前缀之后的字符对应的节点一定在最后一个共同节点的子树中。例如,"can" 和 "cat" 的共同前缀 "ca" 在前缀树中的最后一个节点是第 3 层的第 1 个节点,两个字符串共同的前缀之后的字符 'n' 和 't' 都在最后一个公共节点的子树之中。

字符串在前缀树中的路径并不一定终止于叶节点。如果一个单词是另一个单词的前缀,那么较短的单词对应的路径是较长的单词对应的路径的一部分。例如,在上图中,字符串 "in" 对应的路径是字符串 "inn" 对应的路径的一部分。

如果前缀树路径到达某个节点时它表示了一个完整的字符串,那么字符串最后一个字符对应的节点有特殊的标识。例如,上图中字符串最后一个字符对应的节点都用灰色背景标识。从根节点出发到达表示字符 'i' 的节点,由于该节点被标识为字符串的最后一个字符,因此此时路径表示的字符串 "i" 是字典中的一个单词。接着往下到达表示字符 'n' 的节点,这个节点也被标识为字符串的最后一个字符,因此此时路径表示的字符串 "in" 是字典中的一个单词。接着往下到达另一个表示字符 'n' 的节点,该节点也有同样的标识,因此此时路径表示的字符串 "inn" 是字典中的另一个单词。

在本章中如果没有特殊说明,那么前缀树中都只包含英文小写字母


二、实现前缀树

题目

请设计实现一棵前缀树 Trie,它有如下操作:

  • 函数 insert,在前缀树中添加一个字符串。

  • 函数 search,查找字符串。如果前缀树中包含该字符串,则返回 true;否则返回 false。

  • 函数 startWith,查找字符串前缀。如果前缀树中包含以该前缀开头的字符串,则返回 true;否则返回 false。

例如,调用函数 insert 在前缀树中添加单词 "goodbye" 之后,输入 "good" 调用函数 search 返回 false,但输入 "good" 调用函数 startWith 则返回 true。再次调用函数 insert 添加单词 "good" 之后,此时再输入 "good" 调用函数 search 则返回 true。

分析

  1. 首先定义前缀树中节点的数据结构。前缀树中的节点对应字符串中的一个字符。如果只考虑英文小写字母,那么字符可能是从 'a' 到 'z' 的任意一个,因此前缀树中的节点可能有 26 个子节点。可以将 26 个子节点放到一个数组中,数组中的第 1 个元素是对应字母 'a' 的子节点,第 2 个元素是对应字母 'b' 的子节点,其余的以此类推

    值得注意的是,前缀树的节点中没有一个字段表示节点对应的字符。这是因为可以通过节点是其父节点的第几个子节点得知它对应的字符,也就没有必要在节点中添加一个字段

    节点中还需要一个布尔类型的字段表示到达该节点的路径对应的字符串是否为字典中一个完整的单词

    struct TrieNode {vector<TrieNode*> children;  // 指向子节点的指针数组bool isWord;  // 布尔类型的字段
    ​TrieNode() : children(26, nullptr), isWord(false) {}
    };
  2. 在前缀树中添加(insert)单词时,首先到达前缀树的根节点,确定根节点是否有一个子节点和单词的第 1 个字符对应。如果已经有对应的子节点,则前往该子节点。如果该子节点不存在,则创建一个与第 1 个字符对应的子节点,并前往该子节点。接着判断该子节点中是否存在与单词的第 2 个字符相对应的子节点,并以此类推,将单词其他的字符添加到前缀树中

    当单词的所有字符都添加到前缀树中之后,所在的节点对应单词的最后一个字符。为了标识路径到达该节点时已经对应一个完整的单词,需要将该节点的 isWord 设为 true

  3. 接下来考虑如何实现函数 search。还是从前缀树的根节点开始查找。如果根节点没有一个子节点和字符串的第 1 个节点相对应,那么前缀树中自然不存在查找的单词,直接返回 false。如果根节点中存在与第 1 个字符对应的子节点,则前往该子节点,接着匹配单词的第 2 个字符。以此类推,直到到达和字符串最后一个字符对应的节点。如果该节点的 isWord 的值为 true,那么路径到达该节点时正好对应输入的单词,因此前缀树中存在该输入的单词,可以返回 true;否则返回 false

  4. 函数 startWith 和 search 不同,只要前缀树中存在以输入的前缀开头的单词就应该返回 true。当顺着路径逐个匹配输入前缀的字符时,如果某个字符没有节点与之对应,那么可以返回 false。如果一直到前缀的最后一个字符在前缀树中都有节点与之对应,那么说明前缀树中一定存在以该前缀开头的单词。此时无论当前节点的 isWord 的值是什么,都应该返回 true

    class Trie {
    public:Trie() : root(new TrieNode) {}
    ​void insert(string word) {TrieNode* cur = root;for (char ch : word){int index = ch - 'a';if (cur->children[index] == nullptr)cur->children[index] = new TrieNode;cur = cur->children[index];}cur->isWord = true;}
    ​bool search(string word) {TrieNode* cur = root;for (char ch : word){int index = ch - 'a';if (cur->children[index] == nullptr)return false;
    ​cur = cur->children[index];}return cur->isWord;}
    ​bool startsWith(string prefix) {TrieNode* cur = root;for (char ch : prefix){int index = ch - 'a';if (cur->children[index] == nullptr)return false;
    ​cur = cur->children[index];}return true;}
    private:TrieNode* root;
    };

    如果输入的单词的长度为 n,那么函数 insert、search 和 startWith 的时间复杂度都是 O(n)。

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

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

相关文章

python实现常见一元随机变量的概率分布

一. 随机变量 随机变量是一个从样本空间 Ω \Omega Ω到实数空间 R R R的函数&#xff0c;比如随机变量 X X X可以表示投骰子的点数。随机变量一般可以分为两类&#xff1a; 离散型随机变量&#xff1a;随机变量的取值为有限个。连续型随机变量&#xff1a;随机变量的取值是连…

物体检测-系列教程19:YOLOV5 源码解析9 (Focus模块、Model类构造函数)

&#x1f60e;&#x1f60e;&#x1f60e;物体检测-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 13、Focus模块 13.1 基本流程 原始输入图像的格式为&#xff1a;tensor: float32[1,3,64…

南京观海微电子---如何区分LED显示屏与LED背光源?

LED屏绝对不是常见的LED背光源&#xff0c;LED显示屏也被称为电子显示屏或浮动字。由LED点阵和LEDPC面板&#xff0c;通过红&#xff0c;蓝&#xff0c;白&#xff0c;绿LED的亮灭来显示文字&#xff0c;图像&#xff0c;动画&#xff0c;视频&#xff0c;内容。可根据不同的场…

C++ //练习 10.5 在本节对名册(roster)调用equal的例子中,如果两个名册中保存的都是C风格字符串而不是string,会发生什么?

C Primer&#xff08;第5版&#xff09; 练习 10.5 练习 10.5 在本节对名册(roster)调用equal的例子中&#xff0c;如果两个名册中保存的都是C风格字符串而不是string&#xff0c;会发生什么&#xff1f; 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具…

CSP-201912-2-回收站选址

CSP-201912-2-回收站选址 【50分思路-暴力枚举】 #include <iostream> #include <vector> #include <algorithm> using namespace std; struct trashPoint {int x; int y; }; vector<trashPoint>trashList; vector<int>grade(5); int main…

xxl-job异步任务日志打印到调度器任务管理日志

文章目录 1. xxl-job-core模块添加过滤器2. 执行器logback.xml添加过滤器配置3. 测试 1. xxl-job-core模块添加过滤器 package com.xxl.job.core.config;import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.…

Netty之ChannelHandlerMask详解

Netty的ChannelHandlerMask是用于标记ChannelHandler的位掩码。它被用于指示ChannelHandler的事件处理方式。ChannelHandlerMask 定义了ChannelHandler所有事件。 final class ChannelHandlerMask {static final int MASK_EXCEPTION_CAUGHT 1;static final int MASK_CHANNEL_…

SpringBoot多数据源最佳实践

为什么需要spring boot多数据源 最常见的场景就是单体架构系统需要跨库进行业务增删改查,例如一个购车系统可能需要查询用户信息,然后在进行购买汽车的逻辑。而用户表和汽车表可能不在一个数据库中。 如下图所示,可能一个购买汽车的下单流程为: 用户提交请求。 基于id到数…

【InternLM 实战营笔记】浦语·灵笔的图文理解及创作部署、 Lagent 工具调用 Demo

浦语灵笔的图文理解及创作部署 浦语灵笔是基于书生浦语大语言模型研发的视觉-语言大模型&#xff0c;提供出色的图文理解和创作能力&#xff0c;结合了视觉和语言的先进技术&#xff0c;能够实现图像到文本、文本到图像的双向转换。使用浦语灵笔大模型可以轻松的创作一篇图文推…

mybatis原理图,我拿到了梦寐以求的字节跳动和腾讯双offer

Kafka 如何做到支持百万级 TPS &#xff1f; 先用一张思维导图直接告诉你答案&#xff1a; 顺序读写磁盘 生产者写入数据和消费者读取数据都是顺序读写的&#xff0c;先来一张图直观感受一下顺序读写和随机读写的速度&#xff1a; 从图中可以看出传统硬盘或者SSD的顺序读写甚…

MySQL 多表查询 连接查询 外连接

介绍 MySQL 多表查询 连接查询 内连接 外连接分为两种&#xff0c;左外和右外连接&#xff0c; 左外&#xff1a;相当于查询表1(左表)的所有数据 包含 表1和表2交集部分的数据,完全包含左表的数据 右外&#xff1a;相当于查询表2(右表)的所有数据 包含 表1和表2交集部分的数据…

攻防世界例题wp

1.看到_wakeup()函数第一反应要么触发&#xff0c;要么绕过在这里绕过 2.构造payload实例化一个对象后反序列化 3构造脚本如下&#xff1a; 4.因为它是一个绕过的方法所以我们要使用绕过的方法。 5.继续构造payload将上图的1换成2进行绕过 最终的payload为 O:4:"xctf…

消息队列+更新DB极易引发的DB并发修改bug

背景 我们在生产系统中和其他系统进行交互时一般都会通过消息队列来解耦生产者和消费者&#xff0c;然后通过每个使用方消费消息队列的消息的方式来完成消息的消费&#xff0c;并且一般来说我们消费消息后极有可能会操作DB&#xff0c;不过这种方式如果处理不够仔细&#xff0…

[攻防世界]-Web:fileclude解析

查看网页 代码审计&#xff1a; file_get_contents($file2)&#xff1a;读取文件内容并将内容返回 解法一payload&#xff1a; ?file1php://filter/readconvert.base64-encode/resourceflag.php&file2data://text/plain,hello%20ctf 解法二payload&#xff1a;

AI新工具(20240229) Ideogram 1.0先进的文本转图像模型发布;search2ai让 LLM API 支持联网搜索

1: LTX Studio LTX Studio开放测试&#xff0c;用户可以通过输入文本来生成超过25秒的微电影视频 LTX Studio是由著名AI平台Lightricks推出的生成式AI电影制作平台。用户可以通过输入文本来生成超过25秒的微电影视频&#xff0c;并且可以对视频的镜头切换、角色、场景一致性、…

C++的晨曦之旅:开启编程的新篇章

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 一、 命名空间 在 C/C 中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0…

继电保护测试仪

武汉凯迪正大继电保护测试仪主要特点 1&#xff0e;满足现场试验要求。本仪器具有标准的四相电压&#xff0c;三相电流输出&#xff0c;既可对传统的各种继电器及保护装置进行试验&#xff0c;也可对现代各种微机保护进行各种试验&#xff0c;特别是对变压器差功保护和备自投装…

南方电网的能源棋局上,蔚来换电扮演什么角色?

2 月 26 日&#xff0c;南网储能科技与蔚来能源签署协议&#xff0c;将充换电站、储能站、可调负载等聚合资源连接到虚拟电厂平台&#xff0c;推动换电站作为分布式储能在虚拟电厂项目上的应用。 蔚来换电站是国内首个智慧微电网型分布式换电设施&#xff0c;可透过换电订单预…

【递归搜索回溯专栏】前言与本专栏介绍

本专栏内容为&#xff1a;递归&#xff0c;搜索与回溯算法专栏。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;递归搜索回溯专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

【YOLO v5 v7 v8 小目标改进】ODConv:在卷积核所有维度(数量、空间、输入、输出)上应用注意力机制来优化传统动态卷积

ODConv&#xff1a;在卷积核所有维度&#xff08;数量、空间、输入、输出&#xff09;上应用注意力机制来优化传统的动态卷积 提出背景传统动态卷积全维动态卷积效果 小目标涨点YOLO v5 魔改YOLO v7 魔改YOLO v8 魔改 论文&#xff1a;https://openreview.net/pdf?idDmpCfq6Mg…