@@ -55,7 +55,20 @@ mapSum.sum("ap"); // 返回 5 (<u>ap</u>ple + <u>ap</u>p = 3 + 2 = 5)
55
55
56
56
<!-- 这里可写通用的实现逻辑 -->
57
57
58
- 利用哈希表存储每个键的所有前缀子串。
58
+ ** 方法一:哈希表 + 前缀树**
59
+
60
+ 我们用哈希表 $d$ 存放键值对,用前缀树 $t$ 存放键值对的前缀和。前缀树的每个节点包含两个信息:
61
+
62
+ - ` val ` :以该节点为前缀的键值对的值的总和
63
+ - ` children ` :长度为 $26$ 的数组,存放该节点的子节点
64
+
65
+ 插入键值对 $(key, val)$ 时,我们先判断哈希表是否存在该键,如果存在,那么前缀树每个节点的 ` val ` 都要减去该键原来的值,然后再加上新的值。如果不存在,那么前缀树每个节点的 ` val ` 都要加上新的值。
66
+
67
+ 查询前缀和时,我们从前缀树的根节点开始,遍历前缀字符串,如果当前节点的子节点中不存在该字符,那么说明前缀树中不存在该前缀,返回 $0$。否则,继续遍历下一个字符,直到遍历完前缀字符串,返回当前节点的 ` val ` 。
68
+
69
+ 时间复杂度方面,插入键值对的时间复杂度为 $O(n)$,其中 $n$ 为键的长度。查询前缀和的时间复杂度为 $O(m)$,其中 $m$ 为前缀的长度。
70
+
71
+ 空间复杂度 $O(n \times m \times C)$,其中 $n$ 和 $m$ 分别是键的数量以及键的最大长度;而 $C$ 是字符集的大小,本题中 $C = 26$。
59
72
60
73
<!-- tabs:start -->
61
74
@@ -64,23 +77,43 @@ mapSum.sum("ap"); // 返回 5 (<u>ap</u>ple + <u>ap</u>p = 3 + 2 = 5)
64
77
<!-- 这里可写当前语言的特殊实现逻辑 -->
65
78
66
79
``` python
80
+ class Trie :
81
+ def __init__ (self ):
82
+ self .children: List[Trie | None ] = [None ] * 26
83
+ self .val: int = 0
84
+
85
+ def insert (self , w : str , x : int ):
86
+ node = self
87
+ for c in w:
88
+ idx = ord (c) - ord (' a' )
89
+ if node.children[idx] is None :
90
+ node.children[idx] = Trie()
91
+ node = node.children[idx]
92
+ node.val += x
93
+
94
+ def search (self , w : str ) -> int :
95
+ node = self
96
+ for c in w:
97
+ idx = ord (c) - ord (' a' )
98
+ if node.children[idx] is None :
99
+ return 0
100
+ node = node.children[idx]
101
+ return node.val
102
+
103
+
67
104
class MapSum :
105
+
68
106
def __init__ (self ):
69
- """
70
- Initialize your data structure here.
71
- """
72
- self .data = defaultdict(int )
73
- self .t = defaultdict(int )
107
+ self .d = defaultdict(int )
108
+ self .tree = Trie()
74
109
75
110
def insert (self , key : str , val : int ) -> None :
76
- old = self .t[key]
77
- self .t[key] = val
78
- for i in range (1 , len (key) + 1 ):
79
- self .data[key[:i]] += val - old
111
+ x = val - self .d[key]
112
+ self .d[key] = val
113
+ self .tree.insert(key, x)
80
114
81
115
def sum (self , prefix : str ) -> int :
82
- return self .data[prefix]
83
-
116
+ return self .tree.search(prefix)
84
117
85
118
# Your MapSum object will be instantiated and called as such:
86
119
# obj = MapSum()
@@ -93,27 +126,52 @@ class MapSum:
93
126
<!-- 这里可写当前语言的特殊实现逻辑 -->
94
127
95
128
``` java
129
+ class Trie {
130
+ private Trie [] children = new Trie [26 ];
131
+ private int val;
132
+
133
+ public void insert (String w , int x ) {
134
+ Trie node = this ;
135
+ for (int i = 0 ; i < w. length(); ++ i) {
136
+ int idx = w. charAt(i) - ' a' ;
137
+ if (node. children[idx] == null ) {
138
+ node. children[idx] = new Trie ();
139
+ }
140
+ node = node. children[idx];
141
+ node. val += x;
142
+ }
143
+ }
144
+
145
+ public int search (String w ) {
146
+ Trie node = this ;
147
+ for (int i = 0 ; i < w. length(); ++ i) {
148
+ int idx = w. charAt(i) - ' a' ;
149
+ if (node. children[idx] == null ) {
150
+ return 0 ;
151
+ }
152
+ node = node. children[idx];
153
+ }
154
+ return node. val;
155
+ }
156
+ }
157
+
96
158
class MapSum {
97
- private Map<String , Integer > data;
98
- private Map<String , Integer > t;
159
+ private Map<String , Integer > d = new HashMap<> ();
160
+ private Trie trie = new Trie ();
161
+
99
162
100
- /* * Initialize your data structure here. */
101
163
public MapSum () {
102
- data = new HashMap<> ();
103
- t = new HashMap<> ();
164
+
104
165
}
105
166
106
167
public void insert (String key , int val ) {
107
- int old = t. getOrDefault(key, 0 );
108
- t. put(key, val);
109
- for (int i = 1 ; i < key. length() + 1 ; ++ i) {
110
- String k = key. substring(0 , i);
111
- data. put(k, data. getOrDefault(k, 0 ) + (val - old));
112
- }
168
+ int x = val - d. getOrDefault(key, 0 );
169
+ d. put(key, val);
170
+ trie. insert(key, x);
113
171
}
114
172
115
173
public int sum (String prefix ) {
116
- return data . getOrDefault (prefix, 0 );
174
+ return trie . search (prefix);
117
175
}
118
176
}
119
177
@@ -128,27 +186,59 @@ class MapSum {
128
186
### ** C++**
129
187
130
188
``` cpp
131
- class MapSum {
189
+ class Trie {
132
190
public:
133
- unordered_map<string, int> data;
134
- unordered_map<string, int> t;
191
+ Trie()
192
+ : children(26, nullptr) {
193
+ }
135
194
136
- /** Initialize your data structure here. */
195
+ void insert(string& w, int x) {
196
+ Trie* node = this;
197
+ for (char c : w) {
198
+ c -= 'a';
199
+ if (!node->children[c]) {
200
+ node->children[c] = new Trie();
201
+ }
202
+ node = node->children[c];
203
+ node->val += x;
204
+ }
205
+ }
206
+
207
+ int search (string& w) {
208
+ Trie* node = this;
209
+ for (char c : w) {
210
+ c -= 'a';
211
+ if (!node->children[ c] ) {
212
+ return 0;
213
+ }
214
+ node = node->children[ c] ;
215
+ }
216
+ return node->val;
217
+ }
218
+
219
+ private:
220
+ vector<Trie* > children;
221
+ int val = 0;
222
+ };
223
+
224
+ class MapSum {
225
+ public:
137
226
MapSum() {
138
227
}
139
228
140
229
void insert(string key, int val) {
141
- int old = t[ key] ;
142
- t[ key] = val;
143
- for (int i = 1; i < key.size() + 1; ++i) {
144
- string k = key.substr(0, i);
145
- data[ k] += (val - old);
146
- }
230
+ int x = val - d[key];
231
+ d[key] = val;
232
+ trie->insert(key, x);
147
233
}
148
234
149
235
int sum(string prefix) {
150
- return data[ prefix] ;
236
+ return trie->search( prefix) ;
151
237
}
238
+
239
+ private:
240
+ unordered_map<string, int> d;
241
+ Trie* trie = new Trie();
152
242
};
153
243
154
244
/**
@@ -162,30 +252,50 @@ public:
162
252
### **Go**
163
253
164
254
```go
255
+ type trie struct {
256
+ children [26]*trie
257
+ val int
258
+ }
259
+
260
+ func (t *trie) insert(w string, x int) {
261
+ for _, c := range w {
262
+ c -= 'a'
263
+ if t.children[c] == nil {
264
+ t.children[c] = &trie{}
265
+ }
266
+ t = t.children[c]
267
+ t.val += x
268
+ }
269
+ }
270
+
271
+ func (t *trie) search(w string) int {
272
+ for _, c := range w {
273
+ c -= 'a'
274
+ if t.children[c] == nil {
275
+ return 0
276
+ }
277
+ t = t.children[c]
278
+ }
279
+ return t.val
280
+ }
281
+
165
282
type MapSum struct {
166
- data map[string]int
167
- t map[string]int
283
+ d map[string]int
284
+ t *trie
168
285
}
169
286
170
- /** Initialize your data structure here. */
171
287
func Constructor() MapSum {
172
- return MapSum{
173
- data: make(map[string]int),
174
- t: make(map[string]int),
175
- }
288
+ return MapSum{make(map[string]int), &trie{}}
176
289
}
177
290
178
291
func (this *MapSum) Insert(key string, val int) {
179
- old := this.t[key]
180
- this.t[key] = val
181
- for i := 1; i < len(key)+1; i++ {
182
- k := key[:i]
183
- this.data[k] += (val - old)
184
- }
292
+ x := val - this.d[key]
293
+ this.d[key] = val
294
+ this.t.insert(key, x)
185
295
}
186
296
187
297
func (this *MapSum) Sum(prefix string) int {
188
- return this.data[ prefix]
298
+ return this.t.search( prefix)
189
299
}
190
300
191
301
/**
@@ -196,6 +306,70 @@ func (this *MapSum) Sum(prefix string) int {
196
306
*/
197
307
```
198
308
309
+ ### ** TypeScript**
310
+
311
+ ``` ts
312
+ class Trie {
313
+ children: Trie [];
314
+ val: number ;
315
+
316
+ constructor () {
317
+ this .children = new Array (26 );
318
+ this .val = 0 ;
319
+ }
320
+
321
+ insert(w : string , x : number ) {
322
+ let node: Trie = this ;
323
+ for (const c of w ) {
324
+ const i = c .charCodeAt (0 ) - 97 ;
325
+ if (! node .children [i ]) {
326
+ node .children [i ] = new Trie ();
327
+ }
328
+ node = node .children [i ];
329
+ node .val += x ;
330
+ }
331
+ }
332
+
333
+ search(w : string ): number {
334
+ let node: Trie = this ;
335
+ for (const c of w ) {
336
+ const i = c .charCodeAt (0 ) - 97 ;
337
+ if (! node .children [i ]) {
338
+ return 0 ;
339
+ }
340
+ node = node .children [i ];
341
+ }
342
+ return node .val ;
343
+ }
344
+ }
345
+
346
+ class MapSum {
347
+ d: Map <string , number >;
348
+ t: Trie ;
349
+ constructor () {
350
+ this .d = new Map ();
351
+ this .t = new Trie ();
352
+ }
353
+
354
+ insert(key : string , val : number ): void {
355
+ const x = val - (this .d .get (key ) ?? 0 );
356
+ this .d .set (key , val );
357
+ this .t .insert (key , x );
358
+ }
359
+
360
+ sum(prefix : string ): number {
361
+ return this .t .search (prefix );
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Your MapSum object will be instantiated and called as such:
367
+ * var obj = new MapSum()
368
+ * obj.insert(key,val)
369
+ * var param_2 = obj.sum(prefix)
370
+ */
371
+ ```
372
+
199
373
### ** ...**
200
374
201
375
```
0 commit comments