前缀树介绍

ops/2024/12/27 9:01:37/

数风流人物,还看今朝!

前缀树

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

前缀树,也叫做字典树(Trie),是一种专门处理字符串数据的数据结构。它特别适合用来处理和查询大量的字符串,比如词汇表、域名等。

想象一下,你有一大堆单词,你想快速地查找某个单词是否存在,或者找到以某个前缀开始的所有单词。用普通的列表或者哈希表来做这些操作可能不太高效,尤其是当数据量很大时。这时,前缀树就能派上用场了。

前缀树的基本思想是利用字符串的公共前缀来减少查询的时间。它就像一棵倒立的树,每个节点代表一个字符。从根节点开始,每条边代表一个字符,通向下一个节点。这样,整个路径就组成了一个字符串。

举个简单的例子,假设有以下几个单词:cat, car, dog, dart,dac

这样,每个单词都有一条从根节点到叶节点的路径,路径上的字符连起来就是这个单词。

前缀树的厉害之处在于,它可以非常快速地查找以某个前缀开始的单词。比如,如果你想找出所有以 ‘ca’ 开头的单词,你只需要从根节点沿着 ‘c’ 和 ‘a’ 的边走下去,然后收集所有从那个节点出发的路径,就能得到 ‘cat’ 和 ‘car’。

此外,前缀树还可以用来检查一个单词是否已经存在。你只需要沿着单词的每个字符走路径,看是否能到达一个表示单词结束的节点。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。

  • void insert(String word) 向前缀树中插入字符串 word

  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false

  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false

这是208. 实现 Trie (前缀树)

struct Node {vector<Node*>son;bool end ; // 创建一个bool值的end,代表是否是终止节点Node():son(26,NULL),end(false){}
};
class Trie {Node* root = new Node(); // 创建一个根节点// 返回三种数字,0,1,2// 0代表没有这个单词// 1代表有这个单词,但不是结尾// 2代表有这个单词,且是结尾int find(string word) {auto cur = root; // 遍历字符串 word,同时用一个变量 cur 表示当前在 26// 叉树的哪个节点,初始值为 root。for (auto c : word) {c -= 'a';if (cur->son[c] == nullptr) {return 0;} // 如果 word[i] 不是 cur 的儿子,返回 0。search 和// startsWith 收到 0 之后返回 false。cur = cur->son[c]; // 更新 cur 为儿子列表中的相应节点。}// 如果cur->end为true,说明有这个单词,且是结尾// 如果cur->end为false,说明有这个单词,但并不是结尾,中间就结束了return cur->end ? 2 : 1;}public:void insert(string word) {auto cur =root; // 变量 cur 表示当前在 26 叉树的哪个节点,初始值为 root。for (auto c : word) {c -= 'a';// 如果之前没有就新建一个节点if (cur->son[c] == nullptr) {cur->son[c] = new Node();}cur = cur->son[c]; // 更新 cur 为儿子列表中的相应节点。}cur->end = true; // 把end置为空}// search:如果字符串word已经在前缀树当中,返回truebool search(string word) { return find(word) == 2; }// startwith:如果前缀prefix已经在前缀树当中,返回truebool startsWith(string prefix) {// 是1,2都行,0不行return find(prefix) != 0;}
};

很遗憾,在力扣里面是付费的,牛客里面不付费。

这个是1804.实现前缀树II,这里和上面的不同在于,一个是判断word单词是否出现,一个是查询前缀树里,word单词出现了几次,一个是查询前缀树里,是否有单词以pre做前缀,一个是一个是查询前缀树里,有多少单词以pre做前缀

此时的节点是维护pass,end,和nexts数组,如果有节点经过,pass++,一个单词结束end++,维护这两个信息。

// 测试链接 : https://leetcode.cn/problems/implement-trie-ii-prefix-tree/
public class Code01_TrieTree {// 路是数组实现的class Trie{class TrieNode {public int pass;public int end;//单词的结尾public TrieNode[] nexts;public TrieNode() {pass = 0;end = 0;nexts = new TrieNode[26];}}private TrieNode root;public Trie() {root = new TrieNode();}public void insert(String word) {TrieNode node = root;node.pass++;for (int i = 0, path; i < word.length(); i++) { // 从左往右遍历字符path = word.charAt(i) - 'a'; // 由字符,对应成走向哪条路if (node.nexts[path] == null) {node.nexts[path] = new TrieNode();}node = node.nexts[path];node.pass++;}node.end++;}// 如果之前word插入过前缀树,那么此时删掉一次// 如果之前word没有插入过前缀树,那么什么也不做public void erase(String word) {if (countWordsEqualTo(word) > 0) {TrieNode node = root;node.pass--;for (int i = 0, path; i < word.length(); i++) {path = word.charAt(i) - 'a';if (--node.nexts[path].pass == 0) {node.nexts[path] = null;return;}node = node.nexts[path];}node.end--;}}// 查询前缀树里,word单词出现了几次public int countWordsEqualTo(String word) {TrieNode node = root;for (int i = 0, path; i < word.length(); i++) {path = word.charAt(i) - 'a';if (node.nexts[path] == null) {return 0;}node = node.nexts[path];}return node.end;}// 查询前缀树里,有多少单词以pre做前缀public int countWordsStartingWith(String pre) {TrieNode node = root;for (int i = 0, path; i < pre.length(); i++) {path = pre.charAt(i) - 'a';if (node.nexts[path] == null) {return 0;}node = node.nexts[path];}return node.pass;}}

http://www.ppmy.cn/ops/145333.html

相关文章

DDI-GPT:使用知识图谱增强的大模型对药物相互作用进行可解释的预测

DDI-GPT: Explainable Prediction of Drug-Drug Interactions using Large Language Models enhanced with Knowledge Graphs 是一篇关于药物相互作用&#xff08;DDI&#xff09;预测的研究论文&#xff0c;该研究提出了一个深度学习框架DDI-GPT&#xff0c;它通过结合知识图谱…

JS 数组创建、访问、常用方法

文章目录 创建访问常用属性和相关方法1. length 长度属性2. push() 新增元素 - 末尾添加3. unshift() 新增元素 - 开头添加4. pop() 移除元素 - 末尾删除5. shift() 移除元素 - 开头删除6. concat() 复制数组后新增7. slice() 复制数组8. splice() 增删改9. toString() 转字符串…

STM32低功耗模式结合看门狗

STM32低功耗模式结合看门狗 前言 最近做到一个需求要使用STM32的低功耗模式进行长时间待机应用&#xff0c;每隔十分钟发送一次数据到服务器上&#xff0c;当不发送的时候就处于低功耗模式。在经过一段时间的测试以后发现板子过三四天左右就没有数据上传服务器了&#xff0c;…

Llama3.370B超越GPT-4o和Claude3.5 Sonnet

AI领域日新月异&#xff0c;最近AI 领域发生了太多事情&#xff0c;本文就语言大模型Llama 3.3 70B、GPT-4o 和 Claude 3.5 Sonnet进行对比。 12月7日&#xff0c;Meta今年的最终AI模型将要来了。Meta12月6日发布了Llama 3.3&#xff0c;拥有700亿个参数&#xff0c;但其性能与…

MicroDiffusion——采用新的掩码方法和改进的 Transformer 架构,实现了低预算的扩散模型

介绍 论文地址&#xff1a;https://arxiv.org/abs/2407.15811 现代图像生成模型擅长创建自然、高质量的内容&#xff0c;每年生成的图像超过十亿幅。然而&#xff0c;从头开始训练这些模型极其昂贵和耗时。文本到图像&#xff08;T2I&#xff09;扩散模型降低了部分计算成本&a…

每天40分玩转Django:Django部署概述

一、Django部署概述 在开发阶段,我们通常使用Django内置的轻量级开发服务器runserver。但在生产环境中,为了应对大量并发请求,需要使用高性能的WSGI服务器,如Gunicorn、uWSGI等。同时还要配置Nginx等Web服务器作为反向代理,实现负载均衡、静态文件处理等。下面是Django部署的整…

Java数组深入解析:定义、操作、常见问题与高频练习

一、数组的定义 1. 什么是数组 数组是一个容器&#xff0c;用来存储多个相同类型的数据。它属于引用数据类型&#xff0c;可以存储基本数据类型&#xff08;如int、char&#xff09;或者引用数据类型&#xff08;如String、对象&#xff09;。 2. 数组的定义方式 a. 动态初…

windows11家庭版安装docker无法识别基于wsl2的Ubuntu

软件环境&#xff1a;windows11家庭版安装WSL2,Ubuntu22.04&#xff0c;docker4.34.2 问题描述&#xff1a;安装docker时&#xff0c;设置阶段无法识别Ubuntu22.04. 原因&#xff1a;windows11家庭版本默认没有Hyper-V 解决方案&#xff1a;将下述代码保存在新建记事本中&am…