diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/1.jpg b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/1.jpg new file mode 100644 index 000000000..f1cceaf4e Binary files /dev/null and b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/1.jpg differ diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/2.jpg b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/2.jpg new file mode 100644 index 000000000..0c93b547c Binary files /dev/null and b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/2.jpg differ diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/3.jpg b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/3.jpg new file mode 100644 index 000000000..d4cecbafe Binary files /dev/null and b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/3.jpg differ diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/README.md b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/README.md index 53b559b66..e080532fc 100755 --- a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/README.md +++ b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/README.md @@ -1,28 +1,63 @@ # [1948.Delete Duplicate Folders in System][title] -> [!WARNING|style:flat] -> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm) - ## Description +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. + +- For example, `["one", "two", "three"]` represents the path `"/one/two/three"`. + +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. + +- For example, folders `"/a"` and `"/b"` in the file structure below are identical. They (as well as their subfolders) should **all** be marked: + +- `/a` +- `/a/x` +- `/a/x/y` +- `/a/z` +- `/b` +- `/b/x` +- `/b/x/y` +- `/b/z` + +- 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. + +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. -**Example 1:** +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. + +**Example 1:** + +![1](./1.jpg) ``` -Input: a = "11", b = "1" -Output: "100" +Input: paths = [["a"],["c"],["d"],["a","b"],["c","b"],["d","a"]] +Output: [["d"],["d","a"]] +Explanation: The file structure is as shown. +Folders "/a" and "/c" (and their subfolders) are marked for deletion because they both contain an empty +folder named "b". ``` -## 题意 -> ... +**Example 2:** -## 题解 +![2](./2.jpg) -### 思路1 -> ... -Delete Duplicate Folders in System -```go ``` +Input: paths = [["a"],["c"],["a","b"],["c","b"],["a","b","x"],["a","b","x","y"],["w"],["w","y"]] +Output: [["c"],["c","b"],["a"],["a","b"]] +Explanation: The file structure is as shown. +Folders "/a/b/x" and "/w" (and their subfolders) are marked for deletion because they both contain an empty folder named "y". +Note that folders "/a" and "/c" are identical after the deletion, but they are not deleted because they were not marked beforehand. +``` + +**Example 3:** +![3](./3.jpg) + +``` +Input: paths = [["a","b"],["c","d"],["c"],["a"]] +Output: [["c"],["c","d"],["a"],["a","b"]] +Explanation: All folders are unique in the file system. +Note that the returned array can be in a different order as the order does not matter. +``` ## 结语 diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution.go b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution.go index d115ccf5e..8b89fb2ea 100644 --- a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution.go +++ b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution.go @@ -1,5 +1,108 @@ package Solution -func Solution(x bool) bool { - return x +import ( + "fmt" + "sort" + "strings" +) + +type Tree struct { + Value string + ValueIndex map[string]int + Children []*Tree + Del bool +} + +func Solution(paths [][]string) [][]string { + sort.Slice(paths, func(i, j int) bool { + a, b := len(paths[i]), len(paths[j]) + l := min(a, b) + for k := range l { + if paths[i][k] != paths[j][k] { + return paths[i][k] < paths[j][k] + } + } + return a < b + }) + // 将所有的子目录序列化成一个字符串。之前有过这样的题,搞成字符串 + root := &Tree{Value: "/", Children: []*Tree{}, ValueIndex: map[string]int{}} + var buildTree func([]string) + buildTree = func(p []string) { + walker := root + for _, sub := range p { + index, ok := walker.ValueIndex[sub] + if ok { + walker = walker.Children[index] + continue + } + tree := &Tree{ + Value: sub, Children: []*Tree{}, ValueIndex: map[string]int{}, + } + walker.Children = append(walker.Children, tree) + walker.ValueIndex[sub] = len(walker.Children) - 1 + walker = tree + } + } + for _, path := range paths { + buildTree(path) + } + + var buildNodeFlag func(*Tree) string + + pathToNode := map[string][]*Tree{} + buildNodeFlag = func(node *Tree) string { + if node == nil { + return "#" + } + if len(node.Children) == 0 { + return node.Value + "#" + } + sb := strings.Builder{} + for i, c := range node.Children { + tmp := buildNodeFlag(c) + fmt.Sprintf("%d", i) + sb.WriteString(tmp) + } + s := sb.String() + pathToNode[s] = append(pathToNode[s], node) + return node.Value + s + } + buildNodeFlag(root) + for path, nodes := range pathToNode { + if len(path) == 0 { + continue + } + if len(nodes) > 1 { + // 有重复的 + for _, n := range nodes { + n.Del = true + } + } + } + var filterPath func([]string) []string + filterPath = func(cur []string) []string { + walker := root + i := 0 + for ; i < len(cur); i++ { + index := walker.ValueIndex[cur[i]] + if walker.Children[index].Del { + break + } + walker = walker.Children[index] + } + return cur[:i] + } + in := map[string]struct{}{} + var ans [][]string + for _, path := range paths { + res := filterPath(path) + if len(res) > 0 { + key := strings.Join(res, "/") + if _, ok := in[key]; ok { + continue + } + ans = append(ans, res) + in[key] = struct{}{} + } + } + return ans } diff --git a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution_test.go b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution_test.go index 14ff50eb4..364e8e454 100644 --- a/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution_test.go +++ b/leetcode/1901-2000/1948.Delete-Duplicate-Folders-in-System/Solution_test.go @@ -10,12 +10,25 @@ func TestSolution(t *testing.T) { // 测试用例 cases := []struct { name string - inputs bool - expect bool + inputs [][]string + expect [][]string }{ - {"TestCase", true, true}, - {"TestCase", true, true}, - {"TestCase", false, false}, + {"TestCase1", [][]string{ + {"a"}, {"c"}, {"d"}, {"a", "b"}, + {"c", "b"}, {"d", "a"}, + }, [][]string{{"d"}, {"d", "a"}}}, + {"TestCase2", [][]string{ + {"a"}, {"c"}, {"a", "b"}, {"c", "b"}, {"a", "b", "x"}, + {"a", "b", "x", "y"}, {"w"}, {"w", "y"}, + }, [][]string{ + {"a"}, {"a", "b"}, + {"c"}, {"c", "b"}, + }}, + {"TestCase3", [][]string{ + {"a", "b"}, {"c", "d"}, {"c"}, {"a"}, + }, [][]string{ + {"a"}, {"a", "b"}, {"c"}, {"c", "d"}, + }}, } // 开始测试 @@ -30,10 +43,10 @@ func TestSolution(t *testing.T) { } } -// 压力测试 +// 压力测试 func BenchmarkSolution(b *testing.B) { } -// 使用案列 +// 使用案列 func ExampleSolution() { }