@@ -56,20 +56,24 @@ trie.countWordsStartingWith("app"); // 返回 0
56
56
57
57
<!-- 这里可写通用的实现逻辑 -->
58
58
59
+ ** 方法一:数组实现前缀树**
60
+
59
61
前缀树每个节点包括三部分:
60
62
61
63
1 . 指向子节点的指针数组 children,对于本题而言,数组长度为 26,即小写英文字母的数量。` children[0] ` 对应小写字母 a,...,` children[25] ` 对应小写字母 z。
62
- 1 . int 变量 ` count ` ,表示以该节点结尾的字符串个数。
63
- 1 . int 变量 ` preCount ` ,表示以该节点作为前缀节点的字符串个数。
64
+ 1 . int 变量 ` v ` ,表示以该节点结尾的字符串个数。
65
+ 1 . int 变量 ` pv ` ,表示以该节点作为前缀节点的字符串个数。
64
66
65
67
### 1. 插入字符串
66
68
67
69
我们从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:
68
70
69
71
- 子节点存在。沿着指针移动到子节点,继续处理下一个字符。
70
- - 子节点不存在。创建一个新的子节点,记录在 ` children ` 数组的对应位置上,然后沿着指针移动到子节点,让子节点的 ` preCount ` 值加 1。继续搜索下一个字符。
72
+ - 子节点不存在。创建一个新的子节点,记录在 ` children ` 数组的对应位置上,然后沿着指针移动到子节点,让子节点的 ` pv ` 值加 1。继续搜索下一个字符。
73
+
74
+ 重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点的 ` v ` 值加 1。
71
75
72
- 重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点的 ` count ` 值加 1 。
76
+ 时间复杂度 $O(n)$,其中 $n$ 为字符串的长度 。
73
77
74
78
### 2. 查找前缀
75
79
@@ -80,6 +84,14 @@ trie.countWordsStartingWith("app"); // 返回 0
80
84
81
85
重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。
82
86
87
+ 时间复杂度 $O(n)$,其中 $n$ 为字符串的长度。
88
+
89
+ ### 3. 移除字符串
90
+
91
+ 我们从字典树的根节点开始,依次将对应的子节点的 ` pv ` 值减 1,直到搜索完字符串的最后一个字符。然后将当前节点的 ` v ` 值减 1。
92
+
93
+ 时间复杂度 $O(n)$,其中 $n$ 为字符串的长度。
94
+
83
95
<!-- tabs:start -->
84
96
85
97
### ** Python3**
@@ -90,42 +102,41 @@ trie.countWordsStartingWith("app"); // 返回 0
90
102
class Trie :
91
103
def __init__ (self ):
92
104
self .children = [None ] * 26
93
- self .count = 0
94
- self .pre_count = 0
105
+ self .v = self .pv = 0
95
106
96
107
def insert (self , word : str ) -> None :
97
108
node = self
98
109
for c in word:
99
- index = ord (c) - ord (' a' )
100
- if node.children[index ] is None :
101
- node.children[index ] = Trie()
102
- node = node.children[index ]
103
- node.pre_count += 1
104
- node.count += 1
110
+ idx = ord (c) - ord (' a' )
111
+ if node.children[idx ] is None :
112
+ node.children[idx ] = Trie()
113
+ node = node.children[idx ]
114
+ node.pv += 1
115
+ node.v += 1
105
116
106
117
def countWordsEqualTo (self , word : str ) -> int :
107
- node = self ._search_prefix (word)
108
- return 0 if node is None else node.count
118
+ node = self .search (word)
119
+ return 0 if node is None else node.v
109
120
110
121
def countWordsStartingWith (self , prefix : str ) -> int :
111
- node = self ._search_prefix (prefix)
112
- return 0 if node is None else node.pre_count
122
+ node = self .search (prefix)
123
+ return 0 if node is None else node.pv
113
124
114
125
def erase (self , word : str ) -> None :
115
126
node = self
116
127
for c in word:
117
- index = ord (c) - ord (' a' )
118
- node = node.children[index ]
119
- node.pre_count -= 1
120
- node.count -= 1
128
+ idx = ord (c) - ord (' a' )
129
+ node = node.children[idx ]
130
+ node.pv -= 1
131
+ node.v -= 1
121
132
122
- def _search_prefix (self , prefix : str ):
133
+ def search (self , word ):
123
134
node = self
124
- for c in prefix :
125
- index = ord (c) - ord (' a' )
126
- if node.children[index ] is None :
135
+ for c in word :
136
+ idx = ord (c) - ord (' a' )
137
+ if node.children[idx ] is None :
127
138
return None
128
- node = node.children[index ]
139
+ node = node.children[idx ]
129
140
return node
130
141
131
142
@@ -143,57 +154,55 @@ class Trie:
143
154
144
155
``` java
145
156
class Trie {
146
- private Trie [] children;
147
- private int count ;
148
- private int preCount ;
157
+ private Trie [] children = new Trie [ 26 ] ;
158
+ private int v ;
159
+ private int pv ;
149
160
150
161
public Trie () {
151
- children = new Trie [26 ];
152
- count = 0 ;
153
- preCount = 0 ;
162
+
154
163
}
155
164
156
165
public void insert (String word ) {
157
166
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 ();
167
+ for (char c : word. toCharArray() ) {
168
+ c -= ' a' ;
169
+ if (node. children[c ] == null ) {
170
+ node. children[c ] = new Trie ();
162
171
}
163
- node = node. children[index ];
164
- node. preCount += 1 ;
172
+ node = node. children[c ];
173
+ ++ node. pv ;
165
174
}
166
- node. count += 1 ;
175
+ ++ node. v ;
167
176
}
168
177
169
178
public int countWordsEqualTo (String word ) {
170
- Trie node = searchPrefix (word);
171
- return node == null ? 0 : node. count ;
179
+ Trie node = search (word);
180
+ return node == null ? 0 : node. v ;
172
181
}
173
182
174
183
public int countWordsStartingWith (String prefix ) {
175
- Trie node = searchPrefix (prefix);
176
- return node == null ? 0 : node. preCount ;
184
+ Trie node = search (prefix);
185
+ return node == null ? 0 : node. pv ;
177
186
}
178
187
179
188
public void erase (String word ) {
180
189
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 ;
190
+ for (char c : word. toCharArray() ) {
191
+ c -= ' a' ;
192
+ node = node. children[c ];
193
+ -- node. pv ;
185
194
}
186
- node. count -= 1 ;
195
+ -- node. v ;
187
196
}
188
197
189
- private Trie searchPrefix (String prefix ) {
198
+ private Trie search (String word ) {
190
199
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 ) {
200
+ for (char c : word . toCharArray() ) {
201
+ c -= ' a' ;
202
+ if (node. children[c ] == null ) {
194
203
return null ;
195
204
}
196
- node = node. children[index ];
205
+ node = node. children[c ];
197
206
}
198
207
return node;
199
208
}
@@ -209,6 +218,149 @@ class Trie {
209
218
*/
210
219
```
211
220
221
+ ### ** C++**
222
+
223
+ ``` cpp
224
+ class Trie {
225
+ public:
226
+ Trie()
227
+ : children(26)
228
+ , v(0)
229
+ , pv(0) {
230
+ }
231
+
232
+ void insert(string word) {
233
+ Trie* node = this;
234
+ for (char c : word) {
235
+ c -= 'a';
236
+ if (!node->children[c]) {
237
+ node->children[c] = new Trie();
238
+ }
239
+ node = node->children[c];
240
+ ++node->pv;
241
+ }
242
+ ++node->v;
243
+ }
244
+
245
+ int countWordsEqualTo (string word) {
246
+ Trie* node = search(word);
247
+ return node ? node->v : 0;
248
+ }
249
+
250
+ int countWordsStartingWith(string prefix) {
251
+ Trie* node = search(prefix);
252
+ return node ? node->pv : 0;
253
+ }
254
+
255
+ void erase(string word) {
256
+ Trie* node = this;
257
+ for (char c : word) {
258
+ c -= 'a';
259
+ node = node->children[c];
260
+ --node->pv;
261
+ }
262
+ --node->v;
263
+ }
264
+
265
+ private:
266
+ vector<Trie* > children;
267
+ int v, pv;
268
+
269
+ Trie* search(string& word) {
270
+ Trie* node = this;
271
+ for (char c : word) {
272
+ c -= 'a';
273
+ if (!node->children[c]) {
274
+ return nullptr;
275
+ }
276
+ node = node->children[c];
277
+ }
278
+ return node;
279
+ }
280
+ };
281
+
282
+ /**
283
+ * Your Trie object will be instantiated and called as such:
284
+ * Trie* obj = new Trie();
285
+ * obj->insert(word);
286
+ * int param_2 = obj->countWordsEqualTo(word);
287
+ * int param_3 = obj->countWordsStartingWith(prefix);
288
+ * obj->erase(word);
289
+ * /
290
+ ```
291
+
292
+ ### **Go**
293
+
294
+ ```go
295
+ type Trie struct {
296
+ children [26]*Trie
297
+ v int
298
+ pv int
299
+ }
300
+
301
+ func Constructor() (_ Trie) { return }
302
+
303
+ func (this *Trie) Insert(word string) {
304
+ node := this
305
+ for _, c := range word {
306
+ c -= 'a'
307
+ if node.children[c] == nil {
308
+ node.children[c] = &Trie{}
309
+ }
310
+ node = node.children[c]
311
+ node.pv++
312
+ }
313
+ node.v++
314
+ }
315
+
316
+ func (this *Trie) CountWordsEqualTo(word string) int {
317
+ node := this.search(word)
318
+ if node == nil {
319
+ return 0
320
+ }
321
+ return node.v
322
+ }
323
+
324
+ func (this *Trie) CountWordsStartingWith(prefix string) int {
325
+ node := this.search(prefix)
326
+ if node == nil {
327
+ return 0
328
+ }
329
+ return node.pv
330
+ }
331
+
332
+ func (this *Trie) Erase(word string) {
333
+ node := this
334
+ for _, c := range word {
335
+ c -= 'a'
336
+ node = node.children[c]
337
+ node.pv--
338
+ }
339
+ node.v--
340
+ }
341
+
342
+ func (this *Trie) search(word string) *Trie {
343
+ node := this
344
+ for _, c := range word {
345
+ c -= 'a'
346
+ if node.children[c] == nil {
347
+ return nil
348
+ }
349
+ node = node.children[c]
350
+ }
351
+ return node
352
+ }
353
+
354
+ /**
355
+ * Your Trie object will be instantiated and called as such:
356
+ * obj := Constructor();
357
+ * obj.Insert(word);
358
+ * param_2 := obj.CountWordsEqualTo(word);
359
+ * param_3 := obj.CountWordsStartingWith(prefix);
360
+ * obj.Erase(word);
361
+ */
362
+ ```
363
+
212
364
### ** ...**
213
365
214
366
```
0 commit comments