Skip to content

Commit 5cf842f

Browse files
authored
Merge pull request #1265 from 0xff-dev/1948
Add solution and test-cases for problem 1948
2 parents cdefcdf + 6d08c41 commit 5cf842f

File tree

6 files changed

+173
-22
lines changed

6 files changed

+173
-22
lines changed
24.8 KB
Loading
30.3 KB
Loading
11.1 KB
Loading

leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/README.md

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,63 @@
11
# [1948.Delete Duplicate Folders in System][title]
22

3-
> [!WARNING|style:flat]
4-
> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm)
5-
63
## Description
4+
Due to a bug, there are many duplicate folders in a file system. You are given a 2D array `paths`, where `paths[i]` is an array representing an absolute path to the `ith` folder in the file system.
5+
6+
- For example, `["one", "two", "three"]` represents the path `"/one/two/three"`.
7+
8+
Two folders (not necessarily on the same level) are **identical** if they contain the **same non-empty** set of identical subfolders and underlying subfolder structure. The folders **do not** need to be at the root level to be identical. If two or more folders are **identical**, then **mark** the folders as well as all their subfolders.
9+
10+
- For example, folders `"/a"` and `"/b"` in the file structure below are identical. They (as well as their subfolders) should **all** be marked:
11+
12+
- `/a`
13+
- `/a/x`
14+
- `/a/x/y`
15+
- `/a/z`
16+
- `/b`
17+
- `/b/x`
18+
- `/b/x/y`
19+
- `/b/z`
20+
21+
- However, if the file structure also included the path `"/b/w"`, then the folders `"/a"` and `"/b"` would not be identical. Note that `"/a/x"` and `"/b/x"` would still be considered identical even with the added folder.
22+
23+
Once all the identical folders and their subfolders have been marked, the file system will **delete** all of them. The file system only runs the deletion once, so any folders that become identical after the initial deletion are not deleted.
724

8-
**Example 1:**
25+
Return the 2D array `ans` containing the paths of the **remaining** folders after deleting all the marked folders. The paths may be returned in **any** order.
26+
27+
**Example 1:**
28+
29+
![1](./1.jpg)
930

1031
```
11-
Input: a = "11", b = "1"
12-
Output: "100"
32+
Input: paths = [["a"],["c"],["d"],["a","b"],["c","b"],["d","a"]]
33+
Output: [["d"],["d","a"]]
34+
Explanation: The file structure is as shown.
35+
Folders "/a" and "/c" (and their subfolders) are marked for deletion because they both contain an empty
36+
folder named "b".
1337
```
1438

15-
## 题意
16-
> ...
39+
**Example 2:**
1740

18-
## 题解
41+
![2](./2.jpg)
1942

20-
### 思路1
21-
> ...
22-
Delete Duplicate Folders in System
23-
```go
2443
```
44+
Input: paths = [["a"],["c"],["a","b"],["c","b"],["a","b","x"],["a","b","x","y"],["w"],["w","y"]]
45+
Output: [["c"],["c","b"],["a"],["a","b"]]
46+
Explanation: The file structure is as shown.
47+
Folders "/a/b/x" and "/w" (and their subfolders) are marked for deletion because they both contain an empty folder named "y".
48+
Note that folders "/a" and "/c" are identical after the deletion, but they are not deleted because they were not marked beforehand.
49+
```
50+
51+
**Example 3:**
2552

53+
![3](./3.jpg)
54+
55+
```
56+
Input: paths = [["a","b"],["c","d"],["c"],["a"]]
57+
Output: [["c"],["c","d"],["a"],["a","b"]]
58+
Explanation: All folders are unique in the file system.
59+
Note that the returned array can be in a different order as the order does not matter.
60+
```
2661

2762
## 结语
2863

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,108 @@
11
package Solution
22

3-
func Solution(x bool) bool {
4-
return x
3+
import (
4+
"fmt"
5+
"sort"
6+
"strings"
7+
)
8+
9+
type Tree struct {
10+
Value string
11+
ValueIndex map[string]int
12+
Children []*Tree
13+
Del bool
14+
}
15+
16+
func Solution(paths [][]string) [][]string {
17+
sort.Slice(paths, func(i, j int) bool {
18+
a, b := len(paths[i]), len(paths[j])
19+
l := min(a, b)
20+
for k := range l {
21+
if paths[i][k] != paths[j][k] {
22+
return paths[i][k] < paths[j][k]
23+
}
24+
}
25+
return a < b
26+
})
27+
// 将所有的子目录序列化成一个字符串。之前有过这样的题,搞成字符串
28+
root := &Tree{Value: "/", Children: []*Tree{}, ValueIndex: map[string]int{}}
29+
var buildTree func([]string)
30+
buildTree = func(p []string) {
31+
walker := root
32+
for _, sub := range p {
33+
index, ok := walker.ValueIndex[sub]
34+
if ok {
35+
walker = walker.Children[index]
36+
continue
37+
}
38+
tree := &Tree{
39+
Value: sub, Children: []*Tree{}, ValueIndex: map[string]int{},
40+
}
41+
walker.Children = append(walker.Children, tree)
42+
walker.ValueIndex[sub] = len(walker.Children) - 1
43+
walker = tree
44+
}
45+
}
46+
for _, path := range paths {
47+
buildTree(path)
48+
}
49+
50+
var buildNodeFlag func(*Tree) string
51+
52+
pathToNode := map[string][]*Tree{}
53+
buildNodeFlag = func(node *Tree) string {
54+
if node == nil {
55+
return "#"
56+
}
57+
if len(node.Children) == 0 {
58+
return node.Value + "#"
59+
}
60+
sb := strings.Builder{}
61+
for i, c := range node.Children {
62+
tmp := buildNodeFlag(c) + fmt.Sprintf("%d", i)
63+
sb.WriteString(tmp)
64+
}
65+
s := sb.String()
66+
pathToNode[s] = append(pathToNode[s], node)
67+
return node.Value + s
68+
}
69+
buildNodeFlag(root)
70+
for path, nodes := range pathToNode {
71+
if len(path) == 0 {
72+
continue
73+
}
74+
if len(nodes) > 1 {
75+
// 有重复的
76+
for _, n := range nodes {
77+
n.Del = true
78+
}
79+
}
80+
}
81+
var filterPath func([]string) []string
82+
filterPath = func(cur []string) []string {
83+
walker := root
84+
i := 0
85+
for ; i < len(cur); i++ {
86+
index := walker.ValueIndex[cur[i]]
87+
if walker.Children[index].Del {
88+
break
89+
}
90+
walker = walker.Children[index]
91+
}
92+
return cur[:i]
93+
}
94+
in := map[string]struct{}{}
95+
var ans [][]string
96+
for _, path := range paths {
97+
res := filterPath(path)
98+
if len(res) > 0 {
99+
key := strings.Join(res, "/")
100+
if _, ok := in[key]; ok {
101+
continue
102+
}
103+
ans = append(ans, res)
104+
in[key] = struct{}{}
105+
}
106+
}
107+
return ans
5108
}

leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution_test.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,25 @@ func TestSolution(t *testing.T) {
1010
// 测试用例
1111
cases := []struct {
1212
name string
13-
inputs bool
14-
expect bool
13+
inputs [][]string
14+
expect [][]string
1515
}{
16-
{"TestCase", true, true},
17-
{"TestCase", true, true},
18-
{"TestCase", false, false},
16+
{"TestCase1", [][]string{
17+
{"a"}, {"c"}, {"d"}, {"a", "b"},
18+
{"c", "b"}, {"d", "a"},
19+
}, [][]string{{"d"}, {"d", "a"}}},
20+
{"TestCase2", [][]string{
21+
{"a"}, {"c"}, {"a", "b"}, {"c", "b"}, {"a", "b", "x"},
22+
{"a", "b", "x", "y"}, {"w"}, {"w", "y"},
23+
}, [][]string{
24+
{"a"}, {"a", "b"},
25+
{"c"}, {"c", "b"},
26+
}},
27+
{"TestCase3", [][]string{
28+
{"a", "b"}, {"c", "d"}, {"c"}, {"a"},
29+
}, [][]string{
30+
{"a"}, {"a", "b"}, {"c"}, {"c", "d"},
31+
}},
1932
}
2033

2134
// 开始测试
@@ -30,10 +43,10 @@ func TestSolution(t *testing.T) {
3043
}
3144
}
3245

33-
// 压力测试
46+
// 压力测试
3447
func BenchmarkSolution(b *testing.B) {
3548
}
3649

37-
// 使用案列
50+
// 使用案列
3851
func ExampleSolution() {
3952
}

0 commit comments

Comments
 (0)