@@ -122,32 +122,348 @@ tags:
122
122
123
123
<!-- solution:start -->
124
124
125
- ### 方法一
125
+ ### 方法一:字典树 + DFS
126
+
127
+ 我们可以使用字典树来存储文件夹的结构,字典树的每个节点数据如下:
128
+
129
+ - ` children ` :一个字典,键为子文件夹的名称,值为对应的子节点。
130
+ - ` deleted ` :一个布尔值,表示该节点是否被标记为待删除。
131
+
132
+ 我们将所有路径插入到字典树中,然后使用 DFS 遍历字典树,构建每个子树的字符串表示。对于每个子树,如果它的字符串表示已经存在于一个全局字典中,则将该节点和全局字典中的对应节点都标记为待删除。最后,再次使用 DFS 遍历字典树,将未被标记的节点的路径添加到结果列表中。
126
133
127
134
<!-- tabs:start -->
128
135
129
136
#### Python3
130
137
131
138
``` python
132
-
139
+ class Trie :
140
+ def __init__ (self ):
141
+ self .children: Dict[str , " Trie" ] = defaultdict(Trie)
142
+ self .deleted: bool = False
143
+
144
+
145
+ class Solution :
146
+ def deleteDuplicateFolder (self , paths : List[List[str ]]) -> List[List[str ]]:
147
+ root = Trie()
148
+ for path in paths:
149
+ cur = root
150
+ for name in path:
151
+ if cur.children[name] is None :
152
+ cur.children[name] = Trie()
153
+ cur = cur.children[name]
154
+
155
+ g: Dict[str , Trie] = {}
156
+
157
+ def dfs (node : Trie) -> str :
158
+ if not node.children:
159
+ return " "
160
+ subs: List[str ] = []
161
+ for name, child in node.children.items():
162
+ subs.append(f " { name} ( { dfs(child)} ) " )
163
+ s = " " .join(sorted (subs))
164
+ if s in g:
165
+ node.deleted = g[s].deleted = True
166
+ else :
167
+ g[s] = node
168
+ return s
169
+
170
+ def dfs2 (node : Trie) -> None :
171
+ if node.deleted:
172
+ return
173
+ if path:
174
+ ans.append(path[:])
175
+ for name, child in node.children.items():
176
+ path.append(name)
177
+ dfs2(child)
178
+ path.pop()
179
+
180
+ dfs(root)
181
+ ans: List[List[str ]] = []
182
+ path: List[str ] = []
183
+ dfs2(root)
184
+ return ans
133
185
```
134
186
135
187
#### Java
136
188
137
189
``` java
138
-
190
+ class Trie {
191
+ Map<String , Trie > children;
192
+ boolean deleted;
193
+
194
+ public Trie () {
195
+ children = new HashMap<> ();
196
+ deleted = false ;
197
+ }
198
+ }
199
+
200
+ class Solution {
201
+ public List<List<String > > deleteDuplicateFolder (List<List<String > > paths ) {
202
+ Trie root = new Trie ();
203
+ for (List<String > path : paths) {
204
+ Trie cur = root;
205
+ for (String name : path) {
206
+ if (! cur. children. containsKey(name)) {
207
+ cur. children. put(name, new Trie ());
208
+ }
209
+ cur = cur. children. get(name);
210
+ }
211
+ }
212
+
213
+ Map<String , Trie > g = new HashMap<> ();
214
+
215
+ var dfs = new Function<Trie , String > () {
216
+ @Override
217
+ public String apply (Trie node ) {
218
+ if (node. children. isEmpty()) {
219
+ return " " ;
220
+ }
221
+ List<String > subs = new ArrayList<> ();
222
+ for (var entry : node. children. entrySet()) {
223
+ subs. add(entry. getKey() + " (" + apply(entry. getValue()) + " )" );
224
+ }
225
+ Collections . sort(subs);
226
+ String s = String . join(" " , subs);
227
+ if (g. containsKey(s)) {
228
+ node. deleted = true ;
229
+ g. get(s). deleted = true ;
230
+ } else {
231
+ g. put(s, node);
232
+ }
233
+ return s;
234
+ }
235
+ };
236
+
237
+ dfs. apply(root);
238
+
239
+ List<List<String > > ans = new ArrayList<> ();
240
+ List<String > path = new ArrayList<> ();
241
+
242
+ var dfs2 = new Function<Trie , Void > () {
243
+ @Override
244
+ public Void apply (Trie node ) {
245
+ if (node. deleted) {
246
+ return null ;
247
+ }
248
+ if (! path. isEmpty()) {
249
+ ans. add(new ArrayList<> (path));
250
+ }
251
+ for (Map . Entry<String , Trie > entry : node. children. entrySet()) {
252
+ path. add(entry. getKey());
253
+ apply(entry. getValue());
254
+ path. remove(path. size() - 1 );
255
+ }
256
+ return null ;
257
+ }
258
+ };
259
+
260
+ dfs2. apply(root);
261
+
262
+ return ans;
263
+ }
264
+ }
139
265
```
140
266
141
267
#### C++
142
268
143
269
``` cpp
144
-
270
+ class Trie {
271
+ public:
272
+ unordered_map<string, Trie* > children;
273
+ bool deleted = false;
274
+ };
275
+
276
+ class Solution {
277
+ public:
278
+ vector<vector<string >> deleteDuplicateFolder(vector<vector<string >>& paths) {
279
+ Trie* root = new Trie();
280
+
281
+ for (auto& path : paths) {
282
+ Trie* cur = root;
283
+ for (auto& name : path) {
284
+ if (cur->children.find(name) == cur->children.end()) {
285
+ cur->children[name] = new Trie();
286
+ }
287
+ cur = cur->children[name];
288
+ }
289
+ }
290
+
291
+ unordered_map<string, Trie*> g;
292
+
293
+ auto dfs = [&](this auto && dfs, Trie* node) -> string {
294
+ if (node->children.empty()) return "";
295
+
296
+ vector<string> subs;
297
+ for (auto& child : node->children) {
298
+ subs.push_back(child.first + "(" + dfs(child.second) + ")");
299
+ }
300
+ sort (subs.begin(), subs.end());
301
+ string s = "";
302
+ for (auto& sub : subs) s += sub;
303
+
304
+ if (g.contains(s)) {
305
+ node->deleted = true;
306
+ g[s]->deleted = true;
307
+ } else {
308
+ g[s] = node;
309
+ }
310
+ return s;
311
+ };
312
+
313
+ dfs (root);
314
+
315
+ vector<vector<string>> ans;
316
+ vector<string> path;
317
+
318
+ auto dfs2 = [&](this auto&& dfs2, Trie* node) -> void {
319
+ if (node->deleted) return;
320
+ if (!path.empty()) {
321
+ ans.push_back(path);
322
+ }
323
+ for (auto& child : node->children) {
324
+ path.push_back(child.first);
325
+ dfs2 (child.second);
326
+ path.pop_back();
327
+ }
328
+ };
329
+
330
+ dfs2 (root);
331
+
332
+ return ans;
333
+ }
334
+ };
145
335
```
146
336
147
337
#### Go
148
338
149
339
``` go
340
+ type Trie struct {
341
+ children map [string ]*Trie
342
+ deleted bool
343
+ }
344
+
345
+ func NewTrie () *Trie {
346
+ return &Trie{
347
+ children: make (map [string ]*Trie),
348
+ }
349
+ }
350
+
351
+ func deleteDuplicateFolder (paths [][]string ) (ans [][]string ) {
352
+ root := NewTrie ()
353
+ for _ , path := range paths {
354
+ cur := root
355
+ for _ , name := range path {
356
+ if _ , exists := cur.children [name]; !exists {
357
+ cur.children [name] = NewTrie ()
358
+ }
359
+ cur = cur.children [name]
360
+ }
361
+ }
362
+
363
+ g := make (map [string ]*Trie)
364
+
365
+ var dfs func (*Trie) string
366
+ dfs = func (node *Trie) string {
367
+ if len (node.children ) == 0 {
368
+ return " "
369
+ }
370
+ var subs []string
371
+ for name , child := range node.children {
372
+ subs = append (subs, name+" (" +dfs (child)+" )" )
373
+ }
374
+ sort.Strings (subs)
375
+ s := strings.Join (subs, " " )
376
+ if existingNode , exists := g[s]; exists {
377
+ node.deleted = true
378
+ existingNode.deleted = true
379
+ } else {
380
+ g[s] = node
381
+ }
382
+ return s
383
+ }
384
+
385
+ var dfs2 func (*Trie, []string )
386
+ dfs2 = func (node *Trie, path []string ) {
387
+ if node.deleted {
388
+ return
389
+ }
390
+ if len (path) > 0 {
391
+ ans = append (ans, append ([]string {}, path...))
392
+ }
393
+ for name , child := range node.children {
394
+ dfs2 (child, append (path, name))
395
+ }
396
+ }
397
+
398
+ dfs (root)
399
+ dfs2 (root, []string {})
400
+ return ans
401
+ }
402
+ ```
150
403
404
+ #### TypeScript
405
+
406
+ ``` ts
407
+ function deleteDuplicateFolder(paths : string [][]): string [][] {
408
+ class Trie {
409
+ children: { [key : string ]: Trie } = {};
410
+ deleted: boolean = false ;
411
+ }
412
+
413
+ const root = new Trie ();
414
+
415
+ for (const path of paths ) {
416
+ let cur = root ;
417
+ for (const name of path ) {
418
+ if (! cur .children [name ]) {
419
+ cur .children [name ] = new Trie ();
420
+ }
421
+ cur = cur .children [name ];
422
+ }
423
+ }
424
+
425
+ const g: { [key : string ]: Trie } = {};
426
+
427
+ const dfs = (node : Trie ): string => {
428
+ if (Object .keys (node .children ).length === 0 ) return ' ' ;
429
+
430
+ const subs: string [] = [];
431
+ for (const [name, child] of Object .entries (node .children )) {
432
+ subs .push (` ${name }(${dfs (child )}) ` );
433
+ }
434
+ subs .sort ();
435
+ const s = subs .join (' ' );
436
+
437
+ if (g [s ]) {
438
+ node .deleted = true ;
439
+ g [s ].deleted = true ;
440
+ } else {
441
+ g [s ] = node ;
442
+ }
443
+ return s ;
444
+ };
445
+
446
+ dfs (root );
447
+
448
+ const ans: string [][] = [];
449
+ const path: string [] = [];
450
+
451
+ const dfs2 = (node : Trie ): void => {
452
+ if (node .deleted ) return ;
453
+ if (path .length > 0 ) {
454
+ ans .push ([... path ]);
455
+ }
456
+ for (const [name, child] of Object .entries (node .children )) {
457
+ path .push (name );
458
+ dfs2 (child );
459
+ path .pop ();
460
+ }
461
+ };
462
+
463
+ dfs2 (root );
464
+
465
+ return ans ;
466
+ }
151
467
```
152
468
153
469
<!-- tabs:end -->
0 commit comments