Skip to content

Commit 06d81ca

Browse files
committed
feat: add solutions to leetcode problem: No.1804. Implement Trie II (Prefix Tree)
1 parent 9a590c6 commit 06d81ca

File tree

7 files changed

+371
-12
lines changed

7 files changed

+371
-12
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
### 设计
174174

175175
- [实现 Trie (前缀树)](/solution/0200-0299/0208.Implement%20Trie%20%28Prefix%20Tree%29/README.md)
176+
- [实现 Trie (前缀树) II](/solution/1800-1899/1804.Implement%20Trie%20II%20%28Prefix%20Tree%29/README.md)
176177
- [设计哈希集合](/solution/0700-0799/0705.Design%20HashSet/README.md)
177178
- [设计哈希映射](/solution/0700-0799/0706.Design%20HashMap/README.md)
178179

README_EN.md

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Complete solutions to [LeetCode](https://leetcode-cn.com/problemset/all/), [LCOF
166166
### Design
167167

168168
- [Implement Trie (Prefix Tree)](<solution/0200-0299/0208.Implement%20Trie%20(Prefix%20Tree)/README_EN.md>)
169+
- [Implement Trie II (Prefix Tree)](/solution/1800-1899/1804.Implement%20Trie%20II%20%28Prefix%20Tree%29/README_EN.md)
169170
- [Design HashSet](/solution/0700-0799/0705.Design%20HashSet/README_EN.md)
170171
- [Design HashMap](/solution/0700-0799/0706.Design%20HashMap/README_EN.md)
171172

images/contributors.svg

+6-6
Loading

solution/1800-1899/1804.Implement Trie II (Prefix Tree)/README.md

+137-3
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,161 @@ trie.countWordsStartingWith("app"); // 返回 0
5252
<li>保证每次调用 <code>erase</code> 时,字符串 <code>word</code> 总是存在于前缀树中。</li>
5353
</ul>
5454

55-
5655
## 解法
5756

5857
<!-- 这里可写通用的实现逻辑 -->
5958

59+
前缀树每个节点包括三部分:
60+
61+
1. 指向子节点的指针数组 children,对于本题而言,数组长度为 26,即小写英文字母的数量。`children[0]` 对应小写字母 a,...,`children[25]` 对应小写字母 z。
62+
1. int 变量 `count`,表示以该节点结尾的字符串个数。
63+
1. int 变量 `preCount`,表示以该节点作为前缀节点的字符串个数。
64+
65+
### 1. 插入字符串
66+
67+
我们从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:
68+
69+
- 子节点存在。沿着指针移动到子节点,继续处理下一个字符。
70+
- 子节点不存在。创建一个新的子节点,记录在 `children` 数组的对应位置上,然后沿着指针移动到子节点,让子节点的 `preCount` 值加 1。继续搜索下一个字符。
71+
72+
重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点的 `count` 值加 1。
73+
74+
### 2. 查找前缀
75+
76+
我们从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:
77+
78+
- 子节点存在。沿着指针移动到子节点,继续搜索下一个字符。
79+
- 子节点不存在。说明字典树中不包含该前缀,返回空指针。
80+
81+
重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。
82+
6083
<!-- tabs:start -->
6184

6285
### **Python3**
6386

6487
<!-- 这里可写当前语言的特殊实现逻辑 -->
6588

6689
```python
67-
90+
class Trie:
91+
92+
def __init__(self):
93+
self.children = [None] * 26
94+
self.count = 0
95+
self.pre_count = 0
96+
97+
def insert(self, word: str) -> None:
98+
node = self
99+
for c in word:
100+
index = ord(c) - ord('a')
101+
if node.children[index] is None:
102+
node.children[index] = Trie()
103+
node = node.children[index]
104+
node.pre_count += 1
105+
node.count += 1
106+
107+
def countWordsEqualTo(self, word: str) -> int:
108+
node = self._search_prefix(word)
109+
return 0 if node is None else node.count
110+
111+
def countWordsStartingWith(self, prefix: str) -> int:
112+
node = self._search_prefix(prefix)
113+
return 0 if node is None else node.pre_count
114+
115+
def erase(self, word: str) -> None:
116+
node = self
117+
for c in word:
118+
index = ord(c) - ord('a')
119+
node = node.children[index]
120+
node.pre_count -= 1
121+
node.count -= 1
122+
123+
def _search_prefix(self, prefix: str):
124+
node = self
125+
for c in prefix:
126+
index = ord(c) - ord('a')
127+
if node.children[index] is None:
128+
return None
129+
node = node.children[index]
130+
return node
131+
132+
# Your Trie object will be instantiated and called as such:
133+
# obj = Trie()
134+
# obj.insert(word)
135+
# param_2 = obj.countWordsEqualTo(word)
136+
# param_3 = obj.countWordsStartingWith(prefix)
137+
# obj.erase(word)
68138
```
69139

70140
### **Java**
71141

72142
<!-- 这里可写当前语言的特殊实现逻辑 -->
73143

74144
```java
75-
145+
class Trie {
146+
private Trie[] children;
147+
private int count;
148+
private int preCount;
149+
150+
public Trie() {
151+
children = new Trie[26];
152+
count = 0;
153+
preCount = 0;
154+
}
155+
156+
public void insert(String word) {
157+
Trie node = this;
158+
for (int i = 0; i < word.length(); ++i) {
159+
int index = word.charAt(i) - 'a';
160+
if (node.children[index] == null) {
161+
node.children[index] = new Trie();
162+
}
163+
node = node.children[index];
164+
node.preCount += 1;
165+
}
166+
node.count += 1;
167+
}
168+
169+
public int countWordsEqualTo(String word) {
170+
Trie node = searchPrefix(word);
171+
return node == null ? 0 : node.count;
172+
}
173+
174+
public int countWordsStartingWith(String prefix) {
175+
Trie node = searchPrefix(prefix);
176+
return node == null ? 0 : node.preCount;
177+
}
178+
179+
public void erase(String word) {
180+
Trie node = this;
181+
for (int i = 0; i < word.length(); ++i) {
182+
int index = word.charAt(i) - 'a';
183+
node = node.children[index];
184+
node.preCount -= 1;
185+
}
186+
node.count -= 1;
187+
}
188+
189+
private Trie searchPrefix(String prefix) {
190+
Trie node = this;
191+
for (int i = 0; i < prefix.length(); ++i) {
192+
int index = prefix.charAt(i) - 'a';
193+
if (node.children[index] == null) {
194+
return null;
195+
}
196+
node = node.children[index];
197+
}
198+
return node;
199+
}
200+
}
201+
202+
/**
203+
* Your Trie object will be instantiated and called as such:
204+
* Trie obj = new Trie();
205+
* obj.insert(word);
206+
* int param_2 = obj.countWordsEqualTo(word);
207+
* int param_3 = obj.countWordsStartingWith(prefix);
208+
* obj.erase(word);
209+
*/
76210
```
77211

78212
### **...**

solution/1800-1899/1804.Implement Trie II (Prefix Tree)/README_EN.md

+113-3
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,131 @@ trie.countWordsStartingWith(&quot;app&quot;); // return 0
4949
<li>It is guaranteed that for any function call to <code>erase</code>, the string <code>word</code> will exist in the trie.</li>
5050
</ul>
5151

52-
5352
## Solutions
5453

5554
<!-- tabs:start -->
5655

5756
### **Python3**
5857

5958
```python
60-
59+
class Trie:
60+
61+
def __init__(self):
62+
self.children = [None] * 26
63+
self.count = 0
64+
self.pre_count = 0
65+
66+
def insert(self, word: str) -> None:
67+
node = self
68+
for c in word:
69+
index = ord(c) - ord('a')
70+
if node.children[index] is None:
71+
node.children[index] = Trie()
72+
node = node.children[index]
73+
node.pre_count += 1
74+
node.count += 1
75+
76+
def countWordsEqualTo(self, word: str) -> int:
77+
node = self._search_prefix(word)
78+
return 0 if node is None else node.count
79+
80+
def countWordsStartingWith(self, prefix: str) -> int:
81+
node = self._search_prefix(prefix)
82+
return 0 if node is None else node.pre_count
83+
84+
def erase(self, word: str) -> None:
85+
node = self
86+
for c in word:
87+
index = ord(c) - ord('a')
88+
node = node.children[index]
89+
node.pre_count -= 1
90+
node.count -= 1
91+
92+
def _search_prefix(self, prefix: str):
93+
node = self
94+
for c in prefix:
95+
index = ord(c) - ord('a')
96+
if node.children[index] is None:
97+
return None
98+
node = node.children[index]
99+
return node
100+
101+
# Your Trie object will be instantiated and called as such:
102+
# obj = Trie()
103+
# obj.insert(word)
104+
# param_2 = obj.countWordsEqualTo(word)
105+
# param_3 = obj.countWordsStartingWith(prefix)
106+
# obj.erase(word)
61107
```
62108

63109
### **Java**
64110

65111
```java
66-
112+
class Trie {
113+
private Trie[] children;
114+
private int count;
115+
private int preCount;
116+
117+
public Trie() {
118+
children = new Trie[26];
119+
count = 0;
120+
preCount = 0;
121+
}
122+
123+
public void insert(String word) {
124+
Trie node = this;
125+
for (int i = 0; i < word.length(); ++i) {
126+
int index = word.charAt(i) - 'a';
127+
if (node.children[index] == null) {
128+
node.children[index] = new Trie();
129+
}
130+
node = node.children[index];
131+
node.preCount += 1;
132+
}
133+
node.count += 1;
134+
}
135+
136+
public int countWordsEqualTo(String word) {
137+
Trie node = searchPrefix(word);
138+
return node == null ? 0 : node.count;
139+
}
140+
141+
public int countWordsStartingWith(String prefix) {
142+
Trie node = searchPrefix(prefix);
143+
return node == null ? 0 : node.preCount;
144+
}
145+
146+
public void erase(String word) {
147+
Trie node = this;
148+
for (int i = 0; i < word.length(); ++i) {
149+
int index = word.charAt(i) - 'a';
150+
node = node.children[index];
151+
node.preCount -= 1;
152+
}
153+
node.count -= 1;
154+
}
155+
156+
private Trie searchPrefix(String prefix) {
157+
Trie node = this;
158+
for (int i = 0; i < prefix.length(); ++i) {
159+
int index = prefix.charAt(i) - 'a';
160+
if (node.children[index] == null) {
161+
return null;
162+
}
163+
node = node.children[index];
164+
}
165+
return node;
166+
}
167+
}
168+
169+
/**
170+
* Your Trie object will be instantiated and called as such:
171+
* Trie obj = new Trie();
172+
* obj.insert(word);
173+
* int param_2 = obj.countWordsEqualTo(word);
174+
* int param_3 = obj.countWordsStartingWith(prefix);
175+
* obj.erase(word);
176+
*/
67177
```
68178

69179
### **...**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
class Trie {
2+
private Trie[] children;
3+
private int count;
4+
private int preCount;
5+
6+
public Trie() {
7+
children = new Trie[26];
8+
count = 0;
9+
preCount = 0;
10+
}
11+
12+
public void insert(String word) {
13+
Trie node = this;
14+
for (int i = 0; i < word.length(); ++i) {
15+
int index = word.charAt(i) - 'a';
16+
if (node.children[index] == null) {
17+
node.children[index] = new Trie();
18+
}
19+
node = node.children[index];
20+
node.preCount += 1;
21+
}
22+
node.count += 1;
23+
}
24+
25+
public int countWordsEqualTo(String word) {
26+
Trie node = searchPrefix(word);
27+
return node == null ? 0 : node.count;
28+
}
29+
30+
public int countWordsStartingWith(String prefix) {
31+
Trie node = searchPrefix(prefix);
32+
return node == null ? 0 : node.preCount;
33+
}
34+
35+
public void erase(String word) {
36+
Trie node = this;
37+
for (int i = 0; i < word.length(); ++i) {
38+
int index = word.charAt(i) - 'a';
39+
node = node.children[index];
40+
node.preCount -= 1;
41+
}
42+
node.count -= 1;
43+
}
44+
45+
private Trie searchPrefix(String prefix) {
46+
Trie node = this;
47+
for (int i = 0; i < prefix.length(); ++i) {
48+
int index = prefix.charAt(i) - 'a';
49+
if (node.children[index] == null) {
50+
return null;
51+
}
52+
node = node.children[index];
53+
}
54+
return node;
55+
}
56+
}
57+
58+
/**
59+
* Your Trie object will be instantiated and called as such:
60+
* Trie obj = new Trie();
61+
* obj.insert(word);
62+
* int param_2 = obj.countWordsEqualTo(word);
63+
* int param_3 = obj.countWordsStartingWith(prefix);
64+
* obj.erase(word);
65+
*/

0 commit comments

Comments
 (0)