Java 实现 Trie (前缀树)
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 (前缀树)相关推荐
- leetcode 676. Implement Magic Dictionary | 676. 实现一个魔法字典(DFS+Trie 前缀树)
题目 https://leetcode.com/problems/implement-magic-dictionary/description/ 题解 题意理解 前缀树问题,大意是是让你在字典中找到是 ...
- leetcode 677. Map Sum Pairs | 677. 键值映射(Trie前缀树,BFS)
题目 https://leetcode.com/problems/map-sum-pairs/ 题解 基于前缀树实现,可以参考:leetcode 208. Implement Trie (Prefix ...
- python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)...
python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie) 主要包括两部分内容: (1)利用python中的dict实现Trie: ( ...
- LeetCode 208. 实现 Trie (前缀树) —— 提供一套前缀树模板
208. 实现 Trie (前缀树) Ideas 前缀树嘛,直接套模板咯,把之前写的拿过来抄一遍. 提供一下我的模板. Code Python class TrieNode:def __init__( ...
- 208. 实现 Trie (前缀树)
208. 实现 Trie (前缀树) Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键.这一数据结构有相当多的应用情景,例 ...
- leetcode208. 实现 Trie (前缀树)
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert(" ...
- Leetcode —— 208. 实现 Trie (前缀树)(Python)
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie();trie.insert(" ...
- 【LeetCode】【HOT】208. 实现 Trie (前缀树)
[LeetCode][HOT]208. 实现 Trie (前缀树) 文章目录 [LeetCode][HOT]208. 实现 Trie (前缀树) package hot;public class So ...
- leetcode前缀树java_Java实现 LeetCode 208 实现 Trie (前缀树)
208. 实现 Trie (前缀树) 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie() ...
最新文章
- 实战SSM_O2O商铺_28【商品】商品添加之Dao层的实现
- 苹果6屏幕多大_苹果12使用高通X55,10亿买下的英特尔基带何时能派上用场
- LeetCode 540. 有序数组中的单一元素(位运算二分查找)
- 网络通信程序做个瞬间的扫描判断
- SpringCloud微服务:Ribbon和Feign组件,实现服务调用的负载均衡
- SVM支持向量机,我用到的自学材料
- idea中如何查看一个类的方法被那些类调用了,显示方法对应的调用树
- 基于GTID Replication主从数据不一致操作
- 项目组【网站】的项目
- 位图和矢量图区别,PS和AI的区别
- VMware虚拟机的Linux系统访问本地磁盘
- 基于java的小型超市管理系统系统(含源文件)
- 虚假唤醒spurious wakeup
- 下个时代的前端研发,效率还能提升。PxCook 3.0,最高效的设计研发利器
- arm板上sqlite3移植及使用
- 饿饿,饭饭「每日一题」
- CSDN论坛如何能够获得积分呢?
- HTML5制作99乘法表
- 小红书销售情况(EDA/RFM)
- 台式计算机开关键,台式电脑怎么开机
热门文章
- thinkphp5 消息队列thinkphp-queue扩展
- 基于pythonselect.select模块通信的实例讲解
- android 模拟器Genymotion的安装和使用
- es6 ...展开运算符
- 第十三章、创建接口和定义抽象类
- Kali Linux渗透基础知识整理(三):漏洞利用
- 世界三大顶级音响_世界三大汽车赛事是什么?一起来了解一下
- python 爬视频下载_Python爬虫进阶之爬取某视频并下载的实现
- 计算机io工作方式,QEMU/KVM和VirtIO工作模式
- SpringMVC注解驱动标签做了什么操作