Skip to content

Commit cc7484c

Browse files
committed
feat: add solutions to lc/lcof2 problems
lc No.0208 & lcof2 No.062. Implement Trie (Prefix Tree)
1 parent 62d5f6e commit cc7484c

File tree

16 files changed

+1144
-176
lines changed

16 files changed

+1144
-176
lines changed

lcof2/剑指 Offer II 062. 实现前缀树/README.md

+337-1
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,363 @@ trie.search("app"); // 返回 True
5252

5353
<p><meta charset="UTF-8" />注意:本题与主站 208 题相同:<a href="https://leetcode-cn.com/problems/implement-trie-prefix-tree/">https://leetcode-cn.com/problems/implement-trie-prefix-tree/</a>&nbsp;</p>
5454

55-
5655
## 解法
5756

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

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

6286
### **Python3**
6387

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

6690
```python
91+
class Trie:
92+
93+
def __init__(self):
94+
self.children = [None] * 26
95+
self.is_end = False
6796

97+
def insert(self, word: str) -> None:
98+
node = self
99+
for c in word:
100+
idx = ord(c) - ord('a')
101+
if node.children[idx] is None:
102+
node.children[idx] = Trie()
103+
node = node.children[idx]
104+
node.is_end = True
105+
106+
def search(self, word: str) -> bool:
107+
node = self._search_prefix(word)
108+
return node is not None and node.is_end
109+
110+
def startsWith(self, prefix: str) -> bool:
111+
node = self._search_prefix(prefix)
112+
return node is not None
113+
114+
def _search_prefix(self, prefix: str):
115+
node = self
116+
for c in prefix:
117+
idx = ord(c) - ord('a')
118+
if node.children[idx] is None:
119+
return None
120+
node = node.children[idx]
121+
return node
122+
123+
# Your Trie object will be instantiated and called as such:
124+
# obj = Trie()
125+
# obj.insert(word)
126+
# param_2 = obj.search(word)
127+
# param_3 = obj.startsWith(prefix)
68128
```
69129

70130
### **Java**
71131

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

74134
```java
135+
class Trie {
136+
private Trie[] children;
137+
private boolean isEnd;
138+
139+
public Trie() {
140+
children = new Trie[26];
141+
}
142+
143+
public void insert(String word) {
144+
Trie node = this;
145+
for (char c : word.toCharArray()) {
146+
int idx = c - 'a';
147+
if (node.children[idx] == null) {
148+
node.children[idx] = new Trie();
149+
}
150+
node = node.children[idx];
151+
}
152+
node.isEnd = true;
153+
}
154+
155+
public boolean search(String word) {
156+
Trie node = searchPrefix(word);
157+
return node != null && node.isEnd;
158+
}
159+
160+
public boolean startsWith(String prefix) {
161+
Trie node = searchPrefix(prefix);
162+
return node != null;
163+
}
164+
165+
private Trie searchPrefix(String s) {
166+
Trie node = this;
167+
for (char c : s.toCharArray()) {
168+
int idx = c - 'a';
169+
if (node.children[idx] == null) {
170+
return null;
171+
}
172+
node = node.children[idx];
173+
}
174+
return node;
175+
}
176+
}
177+
178+
/**
179+
* Your Trie object will be instantiated and called as such:
180+
* Trie obj = new Trie();
181+
* obj.insert(word);
182+
* boolean param_2 = obj.search(word);
183+
* boolean param_3 = obj.startsWith(prefix);
184+
*/
185+
```
186+
187+
### **JavaScript**
188+
189+
```js
190+
/**
191+
* Initialize your data structure here.
192+
*/
193+
var Trie = function() {
194+
this.children = {};
195+
};
196+
197+
/**
198+
* Inserts a word into the trie.
199+
* @param {string} word
200+
* @return {void}
201+
*/
202+
Trie.prototype.insert = function(word) {
203+
let node = this.children;
204+
for (let char of word) {
205+
if (!node[char]) {
206+
node[char] = {};
207+
}
208+
node = node[char];
209+
}
210+
node.isEnd = true;
211+
};
212+
213+
/**
214+
* Returns if the word is in the trie.
215+
* @param {string} word
216+
* @return {boolean}
217+
*/
218+
Trie.prototype.search = function(word) {
219+
let node = this.searchPrefix(word);
220+
return node != undefined && node.isEnd != undefined;
221+
};
222+
223+
Trie.prototype.searchPrefix = function (prefix) {
224+
let node = this.children;
225+
for (let char of prefix) {
226+
if (!node[char]) return false;
227+
node = node[char];
228+
}
229+
return node;
230+
}
231+
232+
/**
233+
* Returns if there is any word in the trie that starts with the given prefix.
234+
* @param {string} prefix
235+
* @return {boolean}
236+
*/
237+
Trie.prototype.startsWith = function(prefix) {
238+
return this.searchPrefix(prefix);
239+
};
240+
241+
/**
242+
* Your Trie object will be instantiated and called as such:
243+
* var obj = new Trie()
244+
* obj.insert(word)
245+
* var param_2 = obj.search(word)
246+
* var param_3 = obj.startsWith(prefix)
247+
*/
248+
```
249+
250+
### **C++**
251+
252+
```cpp
253+
class Trie {
254+
private:
255+
vector<Trie*> children;
256+
bool isEnd;
257+
258+
Trie* searchPrefix(string s) {
259+
Trie* node = this;
260+
for (char c : s)
261+
{
262+
int idx = c - 'a';
263+
if (!node->children[idx]) return nullptr;
264+
node = node->children[idx];
265+
}
266+
return node;
267+
}
268+
269+
public:
270+
Trie() : children(26), isEnd(false) {}
271+
272+
void insert(string word) {
273+
Trie* node = this;
274+
for (char c : word)
275+
{
276+
int idx = c - 'a';
277+
if (!node->children[idx]) node->children[idx] = new Trie();
278+
node = node->children[idx];
279+
}
280+
node->isEnd = true;
281+
}
282+
283+
bool search(string word) {
284+
Trie* node = searchPrefix(word);
285+
return node != nullptr && node->isEnd;
286+
}
287+
288+
bool startsWith(string prefix) {
289+
Trie* node = searchPrefix(prefix);
290+
return node != nullptr;
291+
}
292+
};
293+
294+
/**
295+
* Your Trie object will be instantiated and called as such:
296+
* Trie* obj = new Trie();
297+
* obj->insert(word);
298+
* bool param_2 = obj->search(word);
299+
* bool param_3 = obj->startsWith(prefix);
300+
*/
301+
```
302+
303+
### **Go**
304+
305+
```go
306+
type Trie struct {
307+
children [26]*Trie
308+
isEnd bool
309+
}
310+
311+
func Constructor() Trie {
312+
return Trie{}
313+
}
314+
315+
func (this *Trie) Insert(word string) {
316+
node := this
317+
for _, c := range word {
318+
idx := c - 'a'
319+
if node.children[idx] == nil {
320+
node.children[idx] = &Trie{}
321+
}
322+
node = node.children[idx]
323+
}
324+
node.isEnd = true
325+
}
326+
327+
func (this *Trie) Search(word string) bool {
328+
node := this.SearchPrefix(word)
329+
return node != nil && node.isEnd
330+
}
331+
332+
func (this *Trie) StartsWith(prefix string) bool {
333+
node := this.SearchPrefix(prefix)
334+
return node != nil
335+
}
336+
337+
func (this *Trie) SearchPrefix(s string) *Trie {
338+
node := this
339+
for _, c := range s {
340+
idx := c - 'a'
341+
if node.children[idx] == nil {
342+
return nil
343+
}
344+
node = node.children[idx]
345+
}
346+
return node
347+
}
348+
349+
/**
350+
* Your Trie object will be instantiated and called as such:
351+
* obj := Constructor();
352+
* obj.Insert(word);
353+
* param_2 := obj.Search(word);
354+
* param_3 := obj.StartsWith(prefix);
355+
*/
356+
```
357+
358+
### **C#**
359+
360+
```cs
361+
public class Trie {
362+
bool isEnd;
363+
Trie[] children = new Trie[26];
364+
365+
public Trie() {
366+
367+
}
368+
369+
public void Insert(string word) {
370+
Trie node = this;
371+
foreach (var c in word)
372+
{
373+
var idx = c - 'a';
374+
node.children[idx] ??= new Trie();
375+
node = node.children[idx];
376+
}
377+
node.isEnd = true;
378+
}
379+
380+
public bool Search(string word) {
381+
Trie node = SearchPrefix(word);
382+
return node != null && node.isEnd;
383+
}
384+
385+
public bool StartsWith(string prefix) {
386+
Trie node = SearchPrefix(prefix);
387+
return node != null;
388+
}
389+
390+
private Trie SearchPrefix(string s) {
391+
Trie node = this;
392+
foreach (var c in s)
393+
{
394+
var idx = c - 'a';
395+
if (node.children[idx] == null)
396+
{
397+
return null;
398+
}
399+
node = node.children[idx];
400+
}
401+
return node;
402+
}
403+
}
75404

405+
/**
406+
* Your Trie object will be instantiated and called as such:
407+
* Trie obj = new Trie();
408+
* obj.Insert(word);
409+
* bool param_2 = obj.Search(word);
410+
* bool param_3 = obj.StartsWith(prefix);
411+
*/
76412
```
77413

78414
### **...**

0 commit comments

Comments
 (0)