LeetCode 热题 100 208. 实现 Trie (前缀树)
LeetCode 热题 100 | 208. 实现 Trie (前缀树)
大家好!今天我们来解决一道经典的算法题——实现 Trie (前缀树)。Trie(发音类似 “try”)是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构在自动补全和拼写检查等场景中有广泛的应用。下面我将详细讲解解题思路,并附上Python代码实现。
一、问题描述
请你实现 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
二、解题思路
核心思想
Trie 树是一种多叉树,每个节点表示一个字符。每个节点可以有多个子节点,每个子节点表示一个不同的字符。Trie 树的每个节点还包含一个标志位,用于标记该节点是否是一个单词的结尾。
实现步骤
-
定义 Trie 节点:
- 每个节点包含一个字典
children
,用于存储子节点。 - 每个节点包含一个布尔值
is_end
,用于标记该节点是否是一个单词的结尾。
- 每个节点包含一个字典
-
插入操作:
- 从根节点开始,逐个字符插入。
- 如果当前字符不存在于当前节点的子节点中,则创建一个新的子节点。
- 移动到下一个子节点,直到插入完所有字符。
- 在最后一个字符的节点上标记
is_end
为True
。
-
搜索操作:
- 从根节点开始,逐个字符查找。
- 如果当前字符不存在于当前节点的子节点中,返回
False
。 - 移动到下一个子节点,直到查找完所有字符。
- 检查最后一个字符的节点的
is_end
标志,如果为True
,返回True
;否则,返回False
。
-
前缀查找操作:
- 从根节点开始,逐个字符查找。
- 如果当前字符不存在于当前节点的子节点中,返回
False
。 - 移动到下一个子节点,直到查找完所有字符。
- 如果成功查找完所有字符,返回
True
。
代码实现
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.rootfor 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.rootfor char in word:if char not in node.children:return Falsenode = node.children[char]return node.is_end # 检查是否是单词结尾def startsWith(self, prefix: str) -> bool:node = self.rootfor char in prefix:if char not in node.children:return Falsenode = node.children[char]return True # 前缀查找成功
代码解析
-
定义 Trie 节点:
TrieNode
类包含一个字典children
和一个布尔值is_end
。
-
插入操作:
- 从根节点开始,逐个字符插入。
- 如果当前字符不存在于当前节点的子节点中,则创建一个新的子节点。
- 移动到下一个子节点,直到插入完所有字符。
- 在最后一个字符的节点上标记
is_end
为True
。
-
搜索操作:
- 从根节点开始,逐个字符查找。
- 如果当前字符不存在于当前节点的子节点中,返回
False
。 - 移动到下一个子节点,直到查找完所有字符。
- 检查最后一个字符的节点的
is_end
标志,如果为True
,返回True
;否则,返回False
。
-
前缀查找操作:
- 从根节点开始,逐个字符查找。
- 如果当前字符不存在于当前节点的子节点中,返回
False
。 - 移动到下一个子节点,直到查找完所有字符。
- 如果成功查找完所有字符,返回
True
。
复杂度分析
-
时间复杂度:
insert
:O(m),其中 m 是单词的长度。search
:O(m),其中 m 是单词的长度。startsWith
:O(m),其中 m 是前缀的长度。
-
空间复杂度:
- O(n * m),其中 n 是插入的单词数量,m 是单词的平均长度。
示例运行
示例1
# 创建 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 树在自动补全和拼写检查等场景中有广泛的应用。希望这篇题解对大家有所帮助,如果有任何问题,欢迎在评论区留言讨论!
关注我,获取更多算法题解和编程技巧!