LeetCode:https://leetcode-cn.com/problems/implement-trie-prefix-tree/

什么是前缀树

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

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

实现前缀树

摘自:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/208-shi-xian-trie-qian-zhui-shu-bao-gua-insert-sea/

这是一种叫做 单词查找树 的结构。它由字符串键中所有的字符构造而成,允许使用被查找键中的字符进行查找。其中包括插入、查找、删除,寻找前缀等操作。接下来先介绍Trie树的基本性质。

先看下面的例子:

现在有5个word,分别为by,by,hello,heat,the。所构成的TrieTree如图所示,其中包含一个根节点,值为空,跟几点所连接的是每个word的第一个字符,每个字符按照同样的方式生成与之连接的字符的TrieTree,在每个word的最末处,表示该word出现了几次。例如:“b”处为0,表示"b"这个单词没有出现过。“y”处为2,表示“by”这个单词出现了两次。

单词查找树之所以有这样的,是由于我们对于其结点的特殊定义。单词查找树的每一个节点都包含了下一个可能出现的字符的链接。从根节点开始,首先经过的是word的首字母所对应的链接,在下一个节点中沿着第二个字符所对应的链接继续前进,在第二个节点中沿着第三个字符所对应的链接向前,这样到达最后一个字符所指向的节点就结束。接下来我们来看对其节点的定义。

TrieNode

定义单词查找树的结点为:

public class TrieNode{public int path;public int end;public HashMap<Character, TrieNode> next;public TrieNode(){path = 0;end = 0;next = new HashMap<>();}
}
  • path:表示当前节点所能链接到其他节点的个数(在删除操作中会用到)
  • end:表示以当前节点为结尾的单词的个数
  • next:HashMap<Character, TrieNode>类型,表示当前节点能链接到的所有节点。

这里next同样可以使用字符数组来表示,例如字符的范围是小写字母,可以以’a’~'z’字符作为索引,这样相比起哈希表来会提高查找速度,但每一个点都含有一个值和26个链接,这样会多出好多空节点,如图所示:

Insert 操作

如同链表的生成过程一样,从根节点开始,如果根节点所连接的节点中没有当前字符,则生成一个值为当前字符的新节点,插入其中;如果有当前字符,则则继续进行匹配,并在过程中对每一个匹配到的节点path进行计数,重复上述过程,直到插完最后一个字符,并在最后一个字符的节点end进行计数,表示已经该单词的插入操作已经完成。

public void insert(String word){if(word == null || word.equals(""))  return ;TrieNode node = root;for(int i = 0; i<word.length(); i++){char ch = word.charAt(i);if(!node.next.containsKey(ch)) {node.next.put(ch,new TrieNode());}node = node.next.get(ch);node.path++;}node.end++;
}

Search 操作

同insert操作基本相同,由于我这里使用的是Hashmap进行的节点存储,故如果在匹配的过程中没能匹配到,则表示搜索失败,匹配到后最后一个字符时,如果当前end值不为零,则表示匹配成功。

public boolean search(String word){if(word == null || word.equals("")) return false;TrieNode node = root;for(int i = 0; i<word.length(); i++){char ch = word.charAt(i);if(!node.next.containsKey(ch)) return false;node = node.next.get(ch);}if(node.end == 0) return false;return true;
}

startwith 操作

同search操作基本相同,只是这里判断到最后一个字符的时候,不需要判断end值。因为这里只需要检查前缀是否存在。

public boolean startsWith(String word){if(word == null || word.equals("")) return false;TrieNode node = root;for(int i = 0; i<word.length(); i++){char ch = word.charAt(i);if(!node.next.containsKey(ch)) return false;node = node.next.get(ch);}return true;
}

delete 操作

delete操作同上述操作大致相同,这里需要使用到path变量,回忆一下,path:表示当前节点所能链接到其他节点的个数。还以五个单词为例,例如删除’the’,当匹配到‘t’时,由于进行path–操作后,此时判断path为0,过可直接将当前节点置空,后面的数据则不用再去遍历即可。java中的垃圾回收机制会处理其他的被断开的节点,如果在C++中,则需要全部匹配,之后调用析构函数去操作。

public void delete(String word){if(word == null || word.equals("") || !search(word)) return ;TrieNode node = root;for (int i = 0; i < word.length(); i++) {char ch = word.charAt(i);if(--node.next.get(ch).path == 0){node.next.remove(ch);return;}node = node.next.get(ch);}node.end--;
}

代码

import java.util.HashMap;public class Trie {private TrieNode root;/*** Initialize your data structure here.*/public Trie() {root = new TrieNode();}/*** Inserts a word into the trie.*/public void insert(String word) {if (word == null || word.equals("")) {return;}TrieNode node = root;for (int i = 0; i < word.length(); i++) {char ch = word.charAt(i);if (!node.next.containsKey(ch)) {node.next.put(ch, new TrieNode());}node = node.next.get(ch);node.path++;}node.end++;}/*** Returns if the word is in the trie.*/public boolean search(String word) {if (word == null || word.equals("")) {return false;}TrieNode node = root;for (int i = 0; i < word.length(); i++) {char ch = word.charAt(i);if (!node.next.containsKey(ch)) {return false;}node = node.next.get(ch);}if (node.end == 0) {return false;}return true;}/*** Returns if there is any word in the trie that starts with the given prefix.*/public boolean startsWith(String prefix) {if (prefix == null || prefix.equals("")) {return false;}TrieNode node = root;for (int i = 0; i < prefix.length(); i++) {char ch = prefix.charAt(i);if (!node.next.containsKey(ch)) {return false;}node = node.next.get(ch);}return true;}public void delete(String word) {if (word == null || word.equals("") || !search(word)) {return;}TrieNode node = root;for (int i = 0; i < word.length(); i++) {char ch = word.charAt(i);if (--node.next.get(ch).path == 0) {node.next.remove(ch);return;}node = node.next.get(ch);}node.end--;}public class TrieNode {public int path;public int end;public HashMap<Character, TrieNode> next;public TrieNode() {this.path = 0;this.end = 0;next = new HashMap<>();}}
}/*** Your Trie object will be instantiated and called as such:* Trie obj = new Trie();* obj.insert(word);* boolean param_2 = obj.search(word);* boolean param_3 = obj.startsWith(prefix);*/

Java 实现 Trie (前缀树)相关推荐

  1. leetcode 676. Implement Magic Dictionary | 676. 实现一个魔法字典(DFS+Trie 前缀树)

    题目 https://leetcode.com/problems/implement-magic-dictionary/description/ 题解 题意理解 前缀树问题,大意是是让你在字典中找到是 ...

  2. leetcode 677. Map Sum Pairs | 677. 键值映射(Trie前缀树,BFS)

    题目 https://leetcode.com/problems/map-sum-pairs/ 题解 基于前缀树实现,可以参考:leetcode 208. Implement Trie (Prefix ...

  3. python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)...

    python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie) 主要包括两部分内容: (1)利用python中的dict实现Trie: ( ...

  4. LeetCode 208. 实现 Trie (前缀树) —— 提供一套前缀树模板

    208. 实现 Trie (前缀树) Ideas 前缀树嘛,直接套模板咯,把之前写的拿过来抄一遍. 提供一下我的模板. Code Python class TrieNode:def __init__( ...

  5. 208. 实现 Trie (前缀树)

    208. 实现 Trie (前缀树) Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键.这一数据结构有相当多的应用情景,例 ...

  6. leetcode208. 实现 Trie (前缀树)

    实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert(" ...

  7. Leetcode —— 208. 实现 Trie (前缀树)(Python)

    实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie();trie.insert(" ...

  8. 【LeetCode】【HOT】208. 实现 Trie (前缀树)

    [LeetCode][HOT]208. 实现 Trie (前缀树) 文章目录 [LeetCode][HOT]208. 实现 Trie (前缀树) package hot;public class So ...

  9. leetcode前缀树java_Java实现 LeetCode 208 实现 Trie (前缀树)

    208. 实现 Trie (前缀树) 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie() ...

最新文章

  1. 实战SSM_O2O商铺_28【商品】商品添加之Dao层的实现
  2. 苹果6屏幕多大_苹果12使用高通X55,10亿买下的英特尔基带何时能派上用场
  3. LeetCode 540. 有序数组中的单一元素(位运算二分查找)
  4. 网络通信程序做个瞬间的扫描判断
  5. SpringCloud微服务:Ribbon和Feign组件,实现服务调用的负载均衡
  6. SVM支持向量机,我用到的自学材料
  7. idea中如何查看一个类的方法被那些类调用了,显示方法对应的调用树
  8. 基于GTID Replication主从数据不一致操作
  9. 项目组【网站】的项目
  10. 位图和矢量图区别,PS和AI的区别
  11. VMware虚拟机的Linux系统访问本地磁盘
  12. 基于java的小型超市管理系统系统(含源文件)
  13. 虚假唤醒spurious wakeup
  14. 下个时代的前端研发,效率还能提升。PxCook 3.0,最高效的设计研发利器
  15. arm板上sqlite3移植及使用
  16. 饿饿,饭饭「每日一题」
  17. CSDN论坛如何能够获得积分呢?
  18. HTML5制作99乘法表
  19. 小红书销售情况(EDA/RFM)
  20. 台式计算机开关键,台式电脑怎么开机

热门文章

  1. thinkphp5 消息队列thinkphp-queue扩展
  2. 基于pythonselect.select模块通信的实例讲解
  3. android 模拟器Genymotion的安装和使用
  4. es6 ...展开运算符
  5. 第十三章、创建接口和定义抽象类
  6. Kali Linux渗透基础知识整理(三):漏洞利用
  7. 世界三大顶级音响_世界三大汽车赛事是什么?一起来了解一下
  8. python 爬视频下载_Python爬虫进阶之爬取某视频并下载的实现
  9. 计算机io工作方式,QEMU/KVM和VirtIO工作模式
  10. SpringMVC注解驱动标签做了什么操作