LeetCode 热题 100 208. 实现 Trie (前缀树)

LeetCode 热题 100 | 208. 实现 Trie (前缀树)

大家好!今天我们来解决一道经典的算法题------实现 Trie (前缀树)。Trie(发音类似 "try")是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构在自动补全和拼写检查等场景中有广泛的应用。下面我将详细讲解解题思路,并附上Python代码实现。


一、问题描述

请你实现 Trie 类,支持以下操作:

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

示例:

plaintext 复制代码
输入
["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

二、解题思路

核心思想

Trie 树是一种多叉树,每个节点表示一个字符。每个节点可以有多个子节点,每个子节点表示一个不同的字符。Trie 树的每个节点还包含一个标志位,用于标记该节点是否是一个单词的结尾。

实现步骤

  1. 定义 Trie 节点:

    • 每个节点包含一个字典 children,用于存储子节点。
    • 每个节点包含一个布尔值 is_end,用于标记该节点是否是一个单词的结尾。
  2. 插入操作:

    • 从根节点开始,逐个字符插入。
    • 如果当前字符不存在于当前节点的子节点中,则创建一个新的子节点。
    • 移动到下一个子节点,直到插入完所有字符。
    • 在最后一个字符的节点上标记 is_end 为 True。
  3. 搜索操作:

    • 从根节点开始,逐个字符查找。
    • 如果当前字符不存在于当前节点的子节点中,返回 False。
    • 移动到下一个子节点,直到查找完所有字符。
    • 检查最后一个字符的节点的 is_end 标志,如果为 True,返回 True;否则,返回 False。
  4. 前缀查找操作:

    • 从根节点开始,逐个字符查找。
    • 如果当前字符不存在于当前节点的子节点中,返回 False。
    • 移动到下一个子节点,直到查找完所有字符。
    • 如果成功查找完所有字符,返回 True。

代码实现

python 复制代码
class TrieNode:
    def __init__(self):
        self.children = {}  # 存储子节点
        self.is_end = False  # 标记是否是一个单词的结尾

class Trie:
    def __init__(self):
        self.root = TrieNode()  # 初始化根节点

    def insert(self, word: str) -> None:
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end = True  # 标记单词结尾

    def search(self, word: str) -> bool:
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end  # 检查是否是单词结尾

    def startsWith(self, prefix: str) -> bool:
        node = self.root
        for char in prefix:
            if char not in node.children:
                return False
            node = node.children[char]
        return True  # 前缀查找成功

代码解析

  1. 定义 Trie 节点:

    • TrieNode 类包含一个字典 children 和一个布尔值 is_end。
  2. 插入操作:

    • 从根节点开始,逐个字符插入。
    • 如果当前字符不存在于当前节点的子节点中,则创建一个新的子节点。
    • 移动到下一个子节点,直到插入完所有字符。
    • 在最后一个字符的节点上标记 is_end 为 True。
  3. 搜索操作:

    • 从根节点开始,逐个字符查找。
    • 如果当前字符不存在于当前节点的子节点中,返回 False。
    • 移动到下一个子节点,直到查找完所有字符。
    • 检查最后一个字符的节点的 is_end 标志,如果为 True,返回 True;否则,返回 False。
  4. 前缀查找操作:

    • 从根节点开始,逐个字符查找。
    • 如果当前字符不存在于当前节点的子节点中,返回 False。
    • 移动到下一个子节点,直到查找完所有字符。
    • 如果成功查找完所有字符,返回 True。

复杂度分析

  • 时间复杂度:

    • insert:O(m),其中 m 是单词的长度。
    • search:O(m),其中 m 是单词的长度。
    • startsWith:O(m),其中 m 是前缀的长度。
  • 空间复杂度:

    • O(n * m),其中 n 是插入的单词数量,m 是单词的平均长度。

示例运行

示例1
python 复制代码
# 创建 Trie 对象
trie = Trie()
# 执行操作
trie.insert("apple")
print(trie.search("apple"))   # 返回 True
print(trie.search("app"))     # 返回 False
print(trie.startsWith("app")) # 返回 True
trie.insert("app")
print(trie.search("app"))     # 返回 True

输出:

复制代码
True
False
True
True

总结

通过实现 Trie 树,我们可以在高效地存储和检索字符串数据集中的键。Trie 树在自动补全和拼写检查等场景中有广泛的应用。希望这篇题解对大家有所帮助,如果有任何问题,欢迎在评论区留言讨论!

关注我,获取更多算法题解和编程技巧!

相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法