Skip to content

Commit 7190e99

Browse files
committed
208
1 parent 6aa0484 commit 7190e99

File tree

3 files changed

+136
-2
lines changed

3 files changed

+136
-2
lines changed

SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,5 @@
186186
* [204. Count Primes](leetcode-204-Count-Primes.md)
187187
* [205. Isomorphic Strings](leetcode-205-Isomorphic-Strings.md)
188188
* [206. Reverse Linked List](leetcode-206-Reverse-Linked-List.md)
189-
* [207. Course Schedule](leetcode-207-Course-Schedule.md)
189+
* [207. Course Schedule](leetcode-207-Course-Schedule.md)
190+
* [208. Implement Trie(Prefix Tree)](leetcode-208-Implement-Trie-Prefix-Tree.md)

leetcode-201-300.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212

1313
<a href="leetcode-206-Reverse-Linked-List.html">206. Reverse Linked List</a>
1414

15-
<a href="leetcode-207-Course-Schedule.html">207. Course Schedule</a>
15+
<a href="leetcode-207-Course-Schedule.html">207. Course Schedule</a>
16+
17+
<a href="leetcode-208-Implement-Trie-Prefix-Tree.html">208. Implement Trie(Prefix Tree)
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/208.jpg)
4+
5+
实现 `Trie` 数,即前缀树。`trie`的发明者 Edward Fredkin 把它读作 `/ˈtriː/ "tree"`。但是,其他作者把它读作`/traɪ/"try"`
6+
7+
# 解法一
8+
9+
算作一个高级的数据结构,实现方式可以通过 `26` 叉树。每个节点存一个字母,根节点不存字母。
10+
11+
```java
12+
"app" "as" "cat" "yes" "year" "you"
13+
root
14+
/ | \
15+
a c y
16+
/ \ | / \
17+
p s a e o
18+
/ | / \ \
19+
p t s a u
20+
|
21+
r
22+
上图中省略了 null 节点,对于第一层画完整了其实是下边的样子, 图示中用 0 代表 null
23+
root
24+
/ | | | | | | | | | | | | | | | | | | | | | | | | \
25+
a 0 c 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 y 0
26+
其它层同理
27+
```
28+
29+
代码的话,我们定义一个节点,每个节点包含一个节点数组,代表 `26` 个孩子。此外,还需要一个 `flag` 变量来标记当前节点是否是某个单词的结束。
30+
31+
```java
32+
class TrieNode {
33+
TrieNode[] children;
34+
boolean flag;
35+
public TrieNode() {
36+
children = new TrieNode[26];
37+
flag = false;
38+
//节点初始化为 null
39+
for (int i = 0; i < 26; i++) {
40+
children[i] = null;
41+
}
42+
}
43+
}
44+
```
45+
46+
然后只需要实现题目中所需要的三个函数即可。其中 `children[0]``a``children[1]``b``children[2]``c`... 依次类推。所以存的时候我们用当前字符减去 `a` ,从而得到相应的 `children` 下标。
47+
48+
```java
49+
class Trie {
50+
class TrieNode {
51+
TrieNode[] children;
52+
boolean flag;
53+
public TrieNode() {
54+
children = new TrieNode[26];
55+
flag = false;
56+
for (int i = 0; i < 26; i++) {
57+
children[i] = null;
58+
}
59+
}
60+
}
61+
62+
TrieNode root;
63+
64+
/** Initialize your data structure here. */
65+
public Trie() {
66+
root = new TrieNode();
67+
}
68+
69+
/** Inserts a word into the trie. */
70+
public void insert(String word) {
71+
char[] array = word.toCharArray();
72+
TrieNode cur = root;
73+
for (int i = 0; i < array.length; i++) {
74+
//当前孩子是否存在
75+
if (cur.children[array[i] - 'a'] == null) {
76+
cur.children[array[i] - 'a'] = new TrieNode();
77+
}
78+
cur = cur.children[array[i] - 'a'];
79+
}
80+
//当前节点代表结束
81+
cur.flag = true;
82+
}
83+
84+
/** Returns if the word is in the trie. */
85+
public boolean search(String word) {
86+
char[] array = word.toCharArray();
87+
TrieNode cur = root;
88+
for (int i = 0; i < array.length; i++) {
89+
//不含有当前节点
90+
if (cur.children[array[i] - 'a'] == null) {
91+
return false;
92+
}
93+
cur = cur.children[array[i] - 'a'];
94+
}
95+
//当前节点是否为是某个单词的结束
96+
return cur.flag;
97+
}
98+
99+
/**
100+
* Returns if there is any word in the trie that starts with the given
101+
* prefix.
102+
*/
103+
public boolean startsWith(String prefix) {
104+
char[] array = prefix.toCharArray();
105+
TrieNode cur = root;
106+
for (int i = 0; i < array.length; i++) {
107+
if (cur.children[array[i] - 'a'] == null) {
108+
return false;
109+
}
110+
cur = cur.children[array[i] - 'a'];
111+
}
112+
return true;
113+
}
114+
115+
};
116+
```
117+
118+
#
119+
120+
只要知道每个节点存字母,路径代表单词,代码就很好写出来了。
121+
122+
前缀树适用于两个场景。
123+
124+
* 统计每个单词出现的次数,代码的话只需要将上边的 `flag` 改成 `int` 类型,然后每次插入的时候计数即可。
125+
126+
当然,我们用 `HashMap` 也可以做到,`key` 是单词,`value` 存这个单词出现的次数即可。但缺点是,当单词很多很多的时候,受到 `Hash` 函数的影响,`hash` 值会经常出现冲突,算法可能退化为 `O(n)``n``key` 的总数。
127+
128+
而对于前缀树,我们查找一个单词出现的次数,始终是 `O(m)``m` 为单词的长度。
129+
130+
* 查找某个前缀的单词,最常见的比如搜索引擎的提示、拼写检查、ip 路由等。
131+

0 commit comments

Comments
 (0)