目录

字典树介绍

字典树二维数组实现

实现思路

代码实现

字典树节点链表实现

实现思路

代码实现


字典树介绍

字典树,又称单词查找树。

其根节点不包含字符,除根节点外每一个节点都只包含一个字符; 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。

如下图所示是apple、was、war、ward构成的字典树。

字典树二维数组实现

字典树的常用基本操作为:插入、查找,删除操作比较少见。

实现思路

  1. 用二维数组 trie[i][j]=k 存储父节点编号为 i、第j个子节点的节点的编号。但是如果单纯以 j 作为子节点的个数则需要一个数组来存储节点代表的字符,而且查找时也并不方便,因此这里在存储时 j=字符-‘a’+1 ,这样 j 的值最大时为26。查找字符c时只需查找 trie[i][j][父节点编号][字符c-‘a’+1]即可。
  2. 用数组flag[k]标识编号为k的节点是否到达单词的结束。如下图apple,‘e’节点就需要被标识。

 例如,以apple、was、war、ward构造字典树:

按照输入顺序构造的逻辑字典树结构如左下图,而在二维数组的存储如右图所示(图中表格对应a到z,部分字母省略)。

//输入apple的构造流程:
1、trie[0]['a']=1; //'a'代表'a'字符所在位置即'a'-'a'+ 1
2、trie[1]['p']=2;
3、trie[2]['p']=3;
4、trie[3]['l']=4;
5、trie[4]['e']=5;flag[5]=true; //此编号为5的节点为结尾

查找单词最小前缀:

按上述方法构造好字典树后(假设构造的是前缀字典树,且树上单词均为完整前缀),需要查找单词最小前缀(以ward为例):

1、trie[0][‘w’] 存在,值为 6  //'w'代表'w'字符所在位置即'w'-'w'+ 1
2、trie[6][‘a’] 存在,值为 7
3、trie[7][‘r’ ]存在,值为 9,且flag[9]=true 即war为一个完整的单词前缀

代码实现


import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;/*** @ClassName TrieArray* @Description TODO* @Author SSRS* @Date 2022-07-07 23:26* @Version 1.0*/
public class TrieArray {private int trie[][];private boolean flag[];//对应编号是否是单词或前缀的结束private int total;//当前总节点数public TrieArray() {trie = new int[100000][28];flag = new boolean[2800000];total = 0;}/*** @MethodName insert* @Description TODO* @Author SSRS* @Date 2022-07-07 23:36* @Param [word]* @ReturnType void*/public void insert(String word) {int parent = 0;boolean flag1 = false;for (char c : word.toCharArray()) {if (trie[parent][c - 'a' + 1]==0){trie[parent][c - 'a' + 1] = total + 1;total++;flag1=false;}else {flag1=true;}parent = trie[parent][c - 'a' + 1];}if (flag1){flag[parent] =true;}else {flag[total] = true;}}/***@MethodName search*@Description TODO 查找单词word的最小前缀,如果没有找到返回其本身*@Author SSRS*@Date 2022-07-07 23:43*@Param [word]*@ReturnType java.lang.String*/public String search(String word) {int parent = 0;StringBuilder result = new StringBuilder();for (char c : word.toCharArray()) {result.append(c);if (trie[parent][c - 'a' + 1] == 0) {break;}if (flag[trie[parent][c - 'a' + 1]]) {return result.toString();}parent = trie[parent][c - 'a' + 1];}return word;}/***@MethodName replaceWords*@Description TODO 648. 单词替换 https://leetcode.cn/problems/replace-words*@Author SSRS*@Date 2022-07-08 12:40*@Param [dictionary, sentence]*@ReturnType java.lang.String*/public String replaceWords(List<String> dictionary, String sentence) {for (String root : dictionary) {insert(root);}String result = "";String[] words = sentence.split(" ");for (String word : words) {result+=search(word)+" ";}return result.trim();}public static void main(String[] args) {String[] dictionaryArr = new String[]{"ca","cat","bat","rat"};List<String> dictionary=Arrays.stream(dictionaryArr).collect(Collectors.toList());String sentence = "the cattle was rattled by the battery";System.out.println(new TrieArray().replaceWords(dictionary,sentence));}}

字典树节点链表实现

实现思路

class Node{private Node[] next; //子节点private int flag; //是否单词结束public Node(int flag){next=new Node[26];this.flag=flag;}
}
  1. 构造Node节点树形结构,一个父节点对应多个子节点;为方便查找,【子节点对应字符-‘a’】 作为子节点位于父节点next[]的数组下标;查找字符c时只需查找 【父节点.next[c-'a']】即可。
  2. 用节点内flag标识该节点是否是单词的结束位置(如有多个相同前缀,flag则代表该相同前缀数目)。

代码实现

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;/***@ClassName Trie*@Description TODO*@Author SSRS*@Date 2022-07-08 12:06*@Version 1.0*/
public class Trie {class Node{private Node[] next; //子节点private int flag; //是否单词结束public Node(int flag){next=new Node[26];this.flag=flag;}}private int total; //节点数public Node root; //根节点public Trie(){total=0;root=new Node(0);}/***@MethodName insert*@Description TODO 插入*@Author SSRS*@Date 2022-07-08 12:39*@Param [word]*@ReturnType void*/public void insert(String word) {Node parent = root;boolean flag1 = false;for (int i=0;i<word.length();i++) {char c=word.charAt(i);if (Objects.isNull(parent.next[c - 'a'])){if (i==word.length()-1){parent.next[c - 'a'] = new Node(1);}else {parent.next[c - 'a'] = new Node(0);}total++;}else {if (i==word.length()-1){parent.next[c - 'a'].flag++;}}parent = parent.next[c - 'a'];}}/***@MethodName search*@Description TODO 查找单词word的最小前缀,如果没有找到返回其本身*@Author SSRS*@Date 2022-07-08 12:39*@Param [word]*@ReturnType java.lang.String*/public String search(String word) {Node parent = root;StringBuilder result = new StringBuilder();for (char c : word.toCharArray()) {result.append(c);if (Objects.isNull(parent.next[c - 'a'])){break;}if (parent.next[c - 'a'].flag>0) {return result.toString();}parent = parent.next[c - 'a'];}return word;}/***@MethodName replaceWords*@Description TODO 648. 单词替换 https://leetcode.cn/problems/replace-words*@Author SSRS*@Date 2022-07-08 12:40*@Param [dictionary, sentence]*@ReturnType java.lang.String*/public String replaceWords(List<String> dictionary, String sentence) {for (String root1 : dictionary) {insert(root1);}String result = "";String[] words = sentence.split(" ");for (String word : words) {result+=search(word)+" ";}return result.trim();}public static void main(String[] args) {String[] dictionaryArr = new String[]{"catt","cat","bat","rat"};List<String> dictionary= Arrays.stream(dictionaryArr).collect(Collectors.toList());String sentence = "the cattle was rattled by the battery";System.out.println(new Trie().replaceWords(dictionary,sentence));}
}

字典树(Trie树)两种实现方式详解相关推荐

  1. PCBA加工中常见的两种焊接方式详解

    PCBA加工中常见的两种焊接方式详解 PCBA加工,两种常见的焊接方式就是回流焊和波峰焊,与手动焊接技术相比,自动焊接技术具有减少人为因素的影响.提高效率.降低成本.提高质量等优势,在PCBA加工中, ...

  2. redis的两种持久化方式详解

    一.背景 在实际开发中,为了保证数据的完整性,防止数据丢失,我们除了在原有的传统数据库保存数据的同时,最好是再用redis持久化再保存一次数据.如果仅仅是使用redis而不进行持久化配置的话,当red ...

  3. (转)离散化:两种离散化方式详解

    引入 离散化,就是把一些很离散的点给重新分配. 举个例子,如果一个坐标轴很长(>1e10),给你1e4个坐标,询问某一个点,坐标比它小的点有多少. 很容易就知道,对于1e4个点,我们不必把他们在 ...

  4. 离散化:两种离散化方式详解

    引入 离散化,就是把一些很离散的点给重新分配. 举个例子,如果一个坐标轴很长(>1e10),给你1e4个坐标,询问某一个点,坐标比它小的点有多少. 很容易就知道,对于1e4个点,我们不必把他们在 ...

  5. oracle mysql连接池配置文件_数据库连接池两种配置方式详解

    数据库连接池: 负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接 ...

  6. 约瑟夫环问题的两种解法(详解)

    约瑟夫环问题的两种解法(详解) 题目: Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓.于是决定了自杀方式,41个人排成一个圆 ...

  7. linux apache两种工作模式详解

    apache两种工作模式详解 刚接触这两个配置时很迷糊,全部开启或全部注释没有几多变化.今天搜索到这么一篇讲得还不错的文章,看了几篇,还是不能完全记住,做一个收藏. 空闲子进程:是指没有正在处理请求的 ...

  8. @Resource,@Autowired,@Inject3种注入方式详解

    转载自 @Resource,@Autowired,@Inject3种注入方式详解 概况 @Resource,@Autowired,@Inject 这3种都是用来注入bean的,它们属于不同的程序中. ...

  9. python类的命名空间_Python之关于类变量的两种赋值区别详解

    我就废话不多说了,还是直接看代码吧! # -*- coding:utf-8 -*- #面试题,写一个方法,将一行字符串中所有的单词数量统计出来 class Person(object): TAG = ...

最新文章

  1. DeepMind科学家:AI对战《星际争霸》胜算几何?
  2. Notification 浏览器右下角弹出提示消息
  3. 如何对batch的数据求Gram矩阵
  4. 2019吉首大学计算机调剂,吉首大学2019年硕士研究生调剂考生复试情况分学院公示...
  5. redis cluster 分布式锁_关于分布式锁原理的一些学习与思考redis分布式锁,zookeeper分布式锁...
  6. 帝国cms php替换,帝国CMS内容关键字替换图片标签解决方法
  7. php curl for win7_win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
  8. 碰上这种 Wi-Fi,iPhone 秒崩!
  9. 机器人模仿人类动作一学就会,还能举一反三了 | 论文
  10. 当使用 position 属性时,请始终设置 !DOCTYPE 声明:当使用 float 属性时,请始终设置 !DOCTYPE 声明:
  11. 让simplejson支持datetime类型的序列化
  12. 【数字信号处理】基于matlab数字信号软阈值+硬阈值+改进阈值小波去噪【含Matlab源码 068期】
  13. 2008r2服务器频繁自动重启,关于Windows server2008频繁重启问题
  14. sql升级重启计算机失败win10,win10系统安装sQL server提示重新启动计算机失败的解决技巧...
  15. 云硬盘备份 | 概览
  16. 量化金融基本模型及方法讲习班系列笔记——‘AI与金融工程’
  17. 一文看懂π型滤波电路原理
  18. vivo s12参数
  19. python切换路径到当前目录
  20. 2分钟学会一个简单USB插入检测电路

热门文章

  1. 走好每一步,基于C实现机器人运动学建模与标定、运动规划、轨迹规划算法
  2. 视频剪辑,人脸贴纸美颜特效数字图像处理背后的技术-Qt版本
  3. 纳什均衡与帕累托最优
  4. mysql insert 空字符报错
  5. [Python]FPG(FP-growth)算法核心实现
  6. 南信大网络工程和计算机科学与技术,南信大最好就业的专业?
  7. wetool个人版_wetoo群发wetool与企业-购买
  8. ROS-3DSLAM(十一)lvi-sam源代码阅读9
  9. 图像处理中的傅立叶变换
  10. [转贴]LINUX新手入门及安装配置FAQv