从小白开始刷算法 前缀树篇 leetcode.208

简介: 从小白开始刷算法 前缀树篇 leetcode.208

序言

虽然算法很难,但不应该就放弃。这是一个学习笔记,希望你们喜欢~

先自己尝试写,大概十几分钟仍然写不出来

看思路,再尝试跟着思路写

仍然写不出来,再看视频

b站up视频推荐:爱学习的饲养员

leetcode其他文章:

数组篇:

从小白开始刷算法 数组篇 leetcode.485

从小白开始刷算法 数组篇 leetcode.283

从小白开始刷算法 数组篇 leetcode.27

链表篇:

从小白开始刷算法 ListNode 链表篇 leetcode.203

从小白开始刷算法 ListNode 链表篇 leetcode.206

队列篇

从小白开始刷算法 ListNode 链表篇 leetcode.933

栈篇

从小白开始刷算法 Stack 栈篇 leetcode.20

从小白开始刷算法 Stack 栈篇 leetcode.496

哈希篇

从小白开始刷算法 Hash 哈希篇 leetcode.217

从小白开始刷算法 Hash 哈希篇 leetcode.705

树篇

从小白开始刷算法 Tree 树篇 先序遍历 leetcode.144

从小白开始刷算法 Tree 树篇 中序遍历 leetcode.94

从小白开始刷算法 Tree 树篇 后序遍历 leetcode.94

堆篇

从小白开始刷算法 Heap 堆篇 最大堆排序 leetcode.215

小白开始刷算法 Heap 堆篇 最小堆排序 leetcode.692

双指针篇

从小白开始刷算法 对撞双指针 leetcode.881

从小白开始刷算法 快慢双指针篇 leetcode.141

二分法篇

从小白开始刷算法 二分法篇 leetcode.704

从小白开始刷算法 二分法篇 leetcode.35

从小白开始刷算法 二分法篇 leetcode.162

从小白开始刷算法 二分法篇 leetcode.74

滑动窗口篇

从小白开始刷算法 滑动窗口篇 leetcode.209

从小白开始刷算法 滑动窗口篇 leetcode.1456

递归篇

从小白开始刷算法 递归篇 leetcode.509

从小白开始刷算法 递归篇 leetcode.206

分治法篇

从小白开始刷算法 分治法篇 leetcode.169

从小白开始刷算法 分治法篇 leetcode.53

回溯法篇

从小白开始刷算法 回溯法篇 leetcode.22

从小白开始刷算法 回溯法篇 leetcode.78

dfs篇

从小白开始刷算法 dfs篇 leetcode.938

从小白开始刷算法 dfs篇 leetcode.200

bfs篇

从小白开始刷算法 bfs篇 leetcode.102

并查集篇

从小白开始刷算法 并查集篇 leetcode.200

[从小白开始刷算法 并查集篇 leetcode.547

记忆化搜索篇

从小白开始刷算法 记忆化搜索篇 leetcode.509

从小白开始刷算法 记忆化搜索篇 leetcode.322

动态规划篇

从小白开始刷算法 动态规划篇 leetcode.509

从小白开始刷算法 动态规划篇 leetcode.62

前缀树篇

难度:中等

题目:

208. 实现Trie(前缀树)

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

请你实现 Trie 类:

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

示例:

输入

[“Trie”, “insert”, “search”, “search”, “startsWith”, “insert”, “search”]

[[], [“apple”], [“apple”], [“app”], [“app”], [“app”], [“app”]]

输出

[null, null, true, false, true, null, true]

解释

Trie trie = new Trie();

trie.insert(“apple”);

trie.search(“apple”); // 返回 True

trie.search(“app”); // 返回 False

trie.startsWith(“app”); // 返回 True

trie.insert(“app”);

trie.search(“app”); // 返回 True

题目来源:力扣(LeetCode)

前缀树介绍

前缀树(Trie树),也称为字典树或单词查找树,是一种用于高效存储和检索字符串集合的数据结构。它通过将字符串拆分成字符序列,并将每个字符作为树的节点,将整个字符串存储在树中。

前缀树的特点是共享公共前缀。在树的根节点到任意节点的路径上,构成的字符序列就是该节点所代表的字符串。这样的设计使得在前缀树中查找字符串或者插入新字符串的操作非常高效。

前缀树常用于解决字符串相关的问题,如字符串的前缀匹配、单词搜索、自动补全和词频统计等。它的主要优势是在大量字符串集合中快速定位目标字符串,具有较高的查询效率和空间利用率。

在前缀树的实现中,每个节点包含一个字符和指向子节点的指针。通常使用数组、哈希表或其他数据结构来存储子节点。另外,可以在每个节点上保存额外的信息,如单词的频率、是否为单词的结束节点等。

前缀树的时间复杂度和空间复杂度取决于存储的字符串数量和字符串的平均长度。在一般情况下,前缀树的查询操作的时间复杂度为O(k),其中k为目标字符串的长度。而前缀树的空间复杂度与存储的字符串数量和字符串的平均长度成正比。

思路

Trie的常见操作包括插入(insert)、搜索(search)和前缀匹配(startsWith):

  • insert操作:将一个字符串逐个字符地插入到Trie中。从根节点开始,检查当前字符是否已经存在于子节点中,如果存在,则继续向下遍历;如果不存在,则创建一个新的子节点。最后,在字符串的最后一个字符节点上标记为终止节点,表示该路径构成了一个完整的字符串。
  • search操作:从根节点开始,逐个字符地遍历字符串。如果字符存在于当前节点的子节点中,则继续向下遍历;如果字符不存在于子节点中,或者遍历到了字符串的最后一个字符但是当前节点没有标记为终止节点,则表示字符串不存在于Trie中。
  • startsWith操作:从根节点开始,逐个字符地遍历前缀字符串。如果字符存在于当前节点的子节点中,则继续向下遍历;如果字符不存在于子节点中,或者遍历到了前缀字符串的最后一个字符,则表示前缀不存在于Trie中。

Trie的优点是能够高效地存储大量的字符串集合,并且支持快速的字符串搜索和前缀匹配。它的时间复杂度主要取决于字符串的长度,而与存储的字符串数量无关。

然而,Trie也有一些缺点。它可能占用较多的内存空间,尤其是在存储大量长字符串时。此外,构建和维护Trie树的操作可能较为复杂,并且对于包含大量不同字符的字符串集合,Trie树的深度可能会很大,导致操作性能下降。

因此,在实际应用中,需要根据具体的需求和场景来选择合适的数据结构,权衡Trie的优点和缺点。

// 仅是我的思路代码,leetcode上大神更厉害
class TrieNode {
  private TrieNode[] children;
  private boolean isEndOfWord;
  public TrieNode() {
      // 26个英文字母
      children = new TrieNode[26]; 
      isEndOfWord = false;
  }
  public void insert(String word) {
      TrieNode curr = this;
      for (char c : word.toCharArray()) {
          //计算字符 c 在字母表中的索引,Trie树用于存储小写字母,
          //字母表中的字符从 'a' 到 'z',用整数索引 0 到 25 表示。
          //ASCII编码中,小写字母 'a' 的整数值是 97
          int index = c - 'a';
          if (curr.children[index] == null) {
              curr.children[index] = new TrieNode();
          }
          curr = curr.children[index];
      }
      curr.isEndOfWord = true;
  }
  public boolean search(String word) {
      TrieNode node = searchPrefix(word);
      return node != null && node.isEndOfWord;
  }
  public boolean startsWith(String prefix) {
      TrieNode node = searchPrefix(prefix);
      return node != null;
  }
  private TrieNode searchPrefix(String prefix) {
      TrieNode curr = this;
      for (char c : prefix.toCharArray()) {
          int index = c - 'a';
          if (curr.children[index] == null) {
              return null;
          }
          curr = curr.children[index];
      }
      return curr;
  }
}
class Trie {
  private TrieNode root;
  public Trie() {
      root = new TrieNode();
  }
  public void insert(String word) {
      root.insert(word);
  }
  public boolean search(String word) {
      return root.search(word);
  }
  public boolean startsWith(String prefix) {
      return root.startsWith(prefix);
  }
}


相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
37 0
|
22天前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
21 2
|
3月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
49 6
|
3月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
48 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
53 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
77 0
|
3月前
|
算法 Java
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
40 0
|
3月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
54 0
|
3月前
|
存储 算法 Java
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
36 0
|
3月前
|
算法 Java 索引
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
35 0