分析
- 定义
Trie
树的节点结构
- 每个节点包含以下信息:
is_end
:标志当前节点是否是某个单词的结束节点
son[26]
:一个数组,用于存储指向 26
个小写英文字母子节点的指针。如果某个字母子节点不存在,则为 nullptr
- 初始化
Trie
树
- 插入单词
insert()
- 从根节点出发,逐字符检查单词:
- 如果当前字符对应的子节点不存在,则创建新节点
- 移动到对应的子节点。
- 最后将当前节点标记为结束节点
is_end = true
- 搜索单词
search()
- 从根节点出发,逐字符遍历单词:
- 如果某字符对应的子节点不存在,返回
false
- 如果全部字符都匹配且最后节点是结束节点,返回
true
- 否则,返回
false
- 检查前缀
startsWith()
- 与
search
类似,但不需要检查是否是结束节点。只要能完整遍历到前缀,返回 true
;否则返回 false
时间复杂度
insert()
:O(n)
,其中 n
是单词长度,每次需要逐字符插入
search()
:O(n)
,需要逐字符查找
startsWith()
:O(n)
,需要逐字符查找
空间复杂度
每个节点存储 26
个指针,整体空间复杂度取决于插入的单词集合的总字符数
C++代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
class Trie
{
public:
// 定义 Trie 树节点类型
struct Node {
Node() {
is_end = false;
for (int i = 0; i < 26; ++i)
son[i] = nullptr;
}
bool is_end; // 当前节点是否是某个单词的结束
Node* son[26]; // 指向 26 个子节点的指针数组
};
Node* root; // Trie 树的根节点
Trie() {
root = new Node(); // 初始化根节点
}
// 插入单词
void insert(string word) {
Node* p = root;
for (char c : word) {
int u = c - 'a'; // 计算字符对应的子节点索引
if (!p->son[u]) // 如果不存在该子节点,则创建新节点
p->son[u] = new Node();
p = p->son[u]; // 移动到子节点
}
p->is_end = true; // 标记单词结束
}
// 搜索单词
bool search(string word) {
Node* p = root;
for (char c : word) {
int u = c - 'a'; // 计算字符对应的子节点索引
if (!p->son[u]) // 如果子节点不存在,返回 false
return false;
p = p->son[u]; // 移动到子节点
}
return p->is_end; // 如果最后是结束节点,返回 true
}
// 检查前缀
bool startsWith(string prefix) {
Node* p = root;
for (char c : prefix) {
int u = c - 'a'; // 计算字符对应的子节点索引
if (!p->son[u]) // 如果子节点不存在,返回 false
return false;
p = p->son[u]; // 移动到子节点
}
return true; // 如果能遍历完整前缀,返回 true
}
};
|