Skip to content

Commit d369cf9

Browse files
authored
feat: add solution for deleting duplicate folders in a file system (#4581)
1 parent c10a2f1 commit d369cf9

File tree

4 files changed

+367
-3
lines changed

4 files changed

+367
-3
lines changed

solution/1900-1999/1948.Delete Duplicate Folders in System/README.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,58 @@ tags:
129129
#### Python3
130130

131131
```python
132-
132+
class TrieNode:
133+
def __init__(self):
134+
self.children = collections.defaultdict(TrieNode)
135+
self.key = ""
136+
self.deleted = False
137+
138+
139+
class Solution:
140+
def deleteDuplicateFolder(self, paths: List[List[str]]) -> List[List[str]]:
141+
root = TrieNode()
142+
143+
for path in paths:
144+
current = root
145+
for folder in path:
146+
current = current.children[folder]
147+
current.key = folder
148+
149+
seen = collections.defaultdict(list)
150+
151+
def dfs(node):
152+
if not node.children:
153+
return ""
154+
keys = []
155+
for key, child in node.children.items():
156+
serialized = dfs(child)
157+
keys.append(f"{key}({serialized})")
158+
keys.sort()
159+
serialized = "".join(keys)
160+
if len(seen[serialized]) > 0:
161+
for duplicate in seen[serialized]:
162+
duplicate.deleted = True
163+
node.deleted = True
164+
seen[serialized].append(node)
165+
return serialized
166+
167+
dfs(root)
168+
169+
result = []
170+
path = []
171+
172+
def collect(node):
173+
if node.deleted:
174+
return
175+
if path:
176+
result.append(path.copy())
177+
for key, child in node.children.items():
178+
path.append(key)
179+
collect(child)
180+
path.pop()
181+
182+
collect(root)
183+
return result
133184
```
134185

135186
#### Java
@@ -147,6 +198,76 @@ tags:
147198
#### Go
148199

149200
```go
201+
type TrieNode struct {
202+
children map[string]*TrieNode
203+
key string
204+
deleted bool
205+
}
206+
207+
func deleteDuplicateFolder(paths [][]string) [][]string {
208+
root := &TrieNode{children: make(map[string]*TrieNode)}
209+
210+
for _, path := range paths {
211+
current := root
212+
for _, folder := range path {
213+
if _, ok := current.children[folder]; !ok {
214+
current.children[folder] = &TrieNode{
215+
children: make(map[string]*TrieNode),
216+
key: folder,
217+
}
218+
}
219+
current = current.children[folder]
220+
}
221+
}
222+
223+
seen := make(map[string]*TrieNode)
224+
var dfs func(*TrieNode) string
225+
dfs = func(node *TrieNode) string {
226+
if node == nil || len(node.children) == 0 {
227+
return ""
228+
}
229+
230+
var keys []string
231+
for key, child := range node.children {
232+
serialized := dfs(child)
233+
keys = append(keys, key+"("+serialized+")")
234+
}
235+
sort.Strings(keys)
236+
serialized := strings.Join(keys, "")
237+
238+
if existing, ok := seen[serialized]; ok {
239+
existing.deleted = true
240+
node.deleted = true
241+
} else {
242+
seen[serialized] = node
243+
}
244+
245+
return serialized
246+
}
247+
dfs(root)
248+
249+
var result [][]string
250+
var path []string
251+
var collect func(*TrieNode)
252+
collect = func(node *TrieNode) {
253+
if node.deleted {
254+
return
255+
}
256+
if len(path) > 0 {
257+
newPath := make([]string, len(path))
258+
copy(newPath, path)
259+
result = append(result, newPath)
260+
}
261+
for key, child := range node.children {
262+
path = append(path, key)
263+
collect(child)
264+
path = path[:len(path)-1]
265+
}
266+
}
267+
collect(root)
268+
269+
return result
270+
}
150271

151272
```
152273

solution/1900-1999/1948.Delete Duplicate Folders in System/README_EN.md

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ folder named "b".
6868
<pre>
6969
<strong>Input:</strong> paths = [[&quot;a&quot;],[&quot;c&quot;],[&quot;a&quot;,&quot;b&quot;],[&quot;c&quot;,&quot;b&quot;],[&quot;a&quot;,&quot;b&quot;,&quot;x&quot;],[&quot;a&quot;,&quot;b&quot;,&quot;x&quot;,&quot;y&quot;],[&quot;w&quot;],[&quot;w&quot;,&quot;y&quot;]]
7070
<strong>Output:</strong> [[&quot;c&quot;],[&quot;c&quot;,&quot;b&quot;],[&quot;a&quot;],[&quot;a&quot;,&quot;b&quot;]]
71-
<strong>Explanation: </strong>The file structure is as shown.
71+
<strong>Explanation: </strong>The file structure is as shown.
7272
Folders &quot;/a/b/x&quot; and &quot;/w&quot; (and their subfolders) are marked for deletion because they both contain an empty folder named &quot;y&quot;.
7373
Note that folders &quot;/a&quot; and &quot;/c&quot; are identical after the deletion, but they are not deleted because they were not marked beforehand.
7474
</pre>
@@ -108,7 +108,58 @@ Note that the returned array can be in a different order as the order does not m
108108
#### Python3
109109

110110
```python
111-
111+
class TrieNode:
112+
def __init__(self):
113+
self.children = collections.defaultdict(TrieNode)
114+
self.key = ""
115+
self.deleted = False
116+
117+
118+
class Solution:
119+
def deleteDuplicateFolder(self, paths: List[List[str]]) -> List[List[str]]:
120+
root = TrieNode()
121+
122+
for path in paths:
123+
current = root
124+
for folder in path:
125+
current = current.children[folder]
126+
current.key = folder
127+
128+
seen = collections.defaultdict(list)
129+
130+
def dfs(node):
131+
if not node.children:
132+
return ""
133+
keys = []
134+
for key, child in node.children.items():
135+
serialized = dfs(child)
136+
keys.append(f"{key}({serialized})")
137+
keys.sort()
138+
serialized = "".join(keys)
139+
if len(seen[serialized]) > 0:
140+
for duplicate in seen[serialized]:
141+
duplicate.deleted = True
142+
node.deleted = True
143+
seen[serialized].append(node)
144+
return serialized
145+
146+
dfs(root)
147+
148+
result = []
149+
path = []
150+
151+
def collect(node):
152+
if node.deleted:
153+
return
154+
if path:
155+
result.append(path.copy())
156+
for key, child in node.children.items():
157+
path.append(key)
158+
collect(child)
159+
path.pop()
160+
161+
collect(root)
162+
return result
112163
```
113164

114165
#### Java
@@ -126,6 +177,76 @@ Note that the returned array can be in a different order as the order does not m
126177
#### Go
127178

128179
```go
180+
type TrieNode struct {
181+
children map[string]*TrieNode
182+
key string
183+
deleted bool
184+
}
185+
186+
func deleteDuplicateFolder(paths [][]string) [][]string {
187+
root := &TrieNode{children: make(map[string]*TrieNode)}
188+
189+
for _, path := range paths {
190+
current := root
191+
for _, folder := range path {
192+
if _, ok := current.children[folder]; !ok {
193+
current.children[folder] = &TrieNode{
194+
children: make(map[string]*TrieNode),
195+
key: folder,
196+
}
197+
}
198+
current = current.children[folder]
199+
}
200+
}
201+
202+
seen := make(map[string]*TrieNode)
203+
var dfs func(*TrieNode) string
204+
dfs = func(node *TrieNode) string {
205+
if node == nil || len(node.children) == 0 {
206+
return ""
207+
}
208+
209+
var keys []string
210+
for key, child := range node.children {
211+
serialized := dfs(child)
212+
keys = append(keys, key+"("+serialized+")")
213+
}
214+
sort.Strings(keys)
215+
serialized := strings.Join(keys, "")
216+
217+
if existing, ok := seen[serialized]; ok {
218+
existing.deleted = true
219+
node.deleted = true
220+
} else {
221+
seen[serialized] = node
222+
}
223+
224+
return serialized
225+
}
226+
dfs(root)
227+
228+
var result [][]string
229+
var path []string
230+
var collect func(*TrieNode)
231+
collect = func(node *TrieNode) {
232+
if node.deleted {
233+
return
234+
}
235+
if len(path) > 0 {
236+
newPath := make([]string, len(path))
237+
copy(newPath, path)
238+
result = append(result, newPath)
239+
}
240+
for key, child := range node.children {
241+
path = append(path, key)
242+
collect(child)
243+
path = path[:len(path)-1]
244+
}
245+
}
246+
collect(root)
247+
248+
return result
249+
}
129250

130251
```
131252

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
type TrieNode struct {
2+
children map[string]*TrieNode
3+
key string
4+
deleted bool
5+
}
6+
7+
func deleteDuplicateFolder(paths [][]string) [][]string {
8+
root := &TrieNode{children: make(map[string]*TrieNode)}
9+
10+
for _, path := range paths {
11+
current := root
12+
for _, folder := range path {
13+
if _, ok := current.children[folder]; !ok {
14+
current.children[folder] = &TrieNode{
15+
children: make(map[string]*TrieNode),
16+
key: folder,
17+
}
18+
}
19+
current = current.children[folder]
20+
}
21+
}
22+
23+
seen := make(map[string]*TrieNode)
24+
var dfs func(*TrieNode) string
25+
dfs = func(node *TrieNode) string {
26+
if node == nil || len(node.children) == 0 {
27+
return ""
28+
}
29+
30+
var keys []string
31+
for key, child := range node.children {
32+
serialized := dfs(child)
33+
keys = append(keys, key+"("+serialized+")")
34+
}
35+
sort.Strings(keys)
36+
serialized := strings.Join(keys, "")
37+
38+
if existing, ok := seen[serialized]; ok {
39+
existing.deleted = true
40+
node.deleted = true
41+
} else {
42+
seen[serialized] = node
43+
}
44+
45+
return serialized
46+
}
47+
dfs(root)
48+
49+
var result [][]string
50+
var path []string
51+
var collect func(*TrieNode)
52+
collect = func(node *TrieNode) {
53+
if node.deleted {
54+
return
55+
}
56+
if len(path) > 0 {
57+
newPath := make([]string, len(path))
58+
copy(newPath, path)
59+
result = append(result, newPath)
60+
}
61+
for key, child := range node.children {
62+
path = append(path, key)
63+
collect(child)
64+
path = path[:len(path)-1]
65+
}
66+
}
67+
collect(root)
68+
69+
return result
70+
}

0 commit comments

Comments
 (0)