跳到正文
第 208 题中等

实现 Trie (前缀树)

Implement Trie (Prefix Tree)

实现 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

 

提示:

  • 1 <= word.length, prefix.length <= 2000
  • word 和 prefix 仅由小写英文字母组成
  • insert、search 和 startsWith 调用次数 总计 不超过 3 * 104 次

解题思路

主解法

26 叉树 · 路径即前缀

每个节点代表一个字符,end 标记单词结尾

Trie 把字符串按字符拆成树:根到某个节点的路径就是一个前缀。插入时沿字符走,没有节点就新建;走完整词后,在最后一个节点打上 end。

分步图解

插入 "map":沿 m → a → … 创建缺失节点,最后一个节点标记 end。

word
map
Trie · 每个节点代表一个字符前缀左子树 · 右子树
·mapend
操作与结果
insert("map")
1 / 3
共享前缀 m→a→t;math 和 mate 在 t 之后分叉,max 在 a 之后分叉。

三个操作的区别只在终点判断:

  • insert:建路径,终点 end = true。
  • search:路径必须存在,并且终点带 end。
  • startsWith:只要求路径存在,不关心终点是否是单词。
图解
Trie · 每个节点代表一个字符前缀
·
m
a
pend
t
hend
eend
xend
end 表示从根到这里的字符恰好构成一个完整单词;仅路径存在不代表单词存在。
操作与结果
search("mat")false
普通节点当前操作已确认 / 结果排除 / 冲突
search(mat) 路径存在却没有 end,返回 false;startsWith(ma) 只检查路径。

自拟词表共享前缀 m → a,然后分成 p、t、x 三条路;math 和 mate 又在 t 后分叉。查询 mat 时路径存在但没有 end,所以 search 返回 false,而 startsWith("ma") 返回 true。

每个操作只走单词长度 L 步,时间 O(L);空间与所有插入单词的总字符数成正比。

时间 O(L)空间 O(总字符数)

易错点

  • search 只检查路径存在:会把前缀误判成完整单词。
  • startsWith 也检查 end:math 还没插入时 ma 会被误判为 false。
  • 插入时忘记在终点打 end:之后 search 永远失败。
  • 用整词哈希表代替 Trie:startsWith 需要扫描所有单词,退化为 O(N·L)。

代码与演示

演示输入依次插入 "map"、"math"、"mate"、"max";查询 search("mat")、startsWith("ma")、search("math")、search("max")

根节点不代表字符;插入单词就是沿字符路径建节点,并在最后一个节点打 end。

Trie · 每个节点代表一个字符前缀左子树 · 右子树
·
操作与结果
初始化空 Trie
1 / 10
查看 C++ 代码

延伸阅读

  • Trie 的节点通常用 26 个指针的数组;字符集很大时可以改用哈希表,节省空间。
  • 前缀树常用于自动补全、拼写检查、单词搜索 II(212)等需要“共享前缀”的场景。