diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/README.md b/solution/1900-1999/1948.Delete Duplicate Folders in System/README.md index 1096aa5c79333..edd3073756909 100644 --- a/solution/1900-1999/1948.Delete Duplicate Folders in System/README.md +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/README.md @@ -5,11 +5,11 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/1900-1999/1948.De rating: 2533 source: 第 251 场周赛 Q4 tags: - - 字典树 - - 数组 - - 哈希表 - - 字符串 - - 哈希函数 + - 字典树 + - 数组 + - 哈希表 + - 字符串 + - 哈希函数 --- @@ -22,13 +22,27 @@ tags: -

由于一个漏洞,文件系统中存在许多重复文件夹。给你一个二维数组 paths,其中 paths[i] 是一个表示文件系统中第 i 个文件夹的绝对路径的数组。

+

+ 由于一个漏洞,文件系统中存在许多重复文件夹。给你一个二维数组{" "} + paths,其中 paths[i] 是一个表示文件系统中第{" "} + i 个文件夹的绝对路径的数组。 +

-

如果两个文件夹(不需要在同一层级)包含 非空且相同的 子文件夹 集合 并具有相同的子文件夹结构,则认为这两个文件夹是相同文件夹。相同文件夹的根层级 需要相同。如果存在两个(或两个以上)相同 文件夹,则需要将这些文件夹和所有它们的子文件夹 标记 为待删除。

+

+ 如果两个文件夹(不需要在同一层级)包含 非空且 + 相同的 子文件夹 集合{" "} + 并具有相同的子文件夹结构,则认为这两个文件夹是相同文件夹。相同文件夹的根层级{" "} + 需要相同。如果存在两个(或两个以上)相同{" "} + 文件夹,则需要将这些文件夹和所有它们的子文件夹 标记{" "} + 为待删除。 +

-

一旦所有的相同文件夹和它们的子文件夹都被标记为待删除,文件系统将会 删除 所有上述文件夹。文件系统只会执行一次删除操作。执行完这一次删除操作后,不会删除新出现的相同文件夹。

+

+ 一旦所有的相同文件夹和它们的子文件夹都被标记为待删除,文件系统将会{" "} + 删除{" "} + 所有上述文件夹。文件系统只会执行一次删除操作。执行完这一次删除操作后,不会删除新出现的相同文件夹。 +

-

返回二维数组 ans ,该数组包含删除所有标记文件夹之后剩余文件夹的路径。路径可以按 任意顺序 返回。

+

+ 返回二维数组 + ans{" "} + ,该数组包含删除所有标记文件夹之后剩余文件夹的路径。路径可以按{" "} + 任意顺序 返回。 +

 

-

示例 1:

- +

+ 示例 1: +

+
-输入:paths = [["a"],["c"],["d"],["a","b"],["c","b"],["d","a"]]
-输出:[["d"],["d","a"]]
-解释:文件结构如上所示。
-文件夹 "/a" 和 "/c"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "b" 的空文件夹。
+  输入:paths =
+  [["a"],["c"],["d"],["a","b"],["c","b"],["d","a"]]
+  输出:[["d"],["d","a"]]
+  解释:文件结构如上所示。 文件夹 "/a" 和
+  "/c"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "b"
+  的空文件夹。
 
-

示例 2:

- +

+ 示例 2: +

+
-输入:paths = [["a"],["c"],["a","b"],["c","b"],["a","b","x"],["a","b","x","y"],["w"],["w","y"]]
-输出:[["c"],["c","b"],["a"],["a","b"]]
-解释:文件结构如上所示。
-文件夹 "/a/b/x" 和 "/w"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "y" 的空文件夹。
-注意,文件夹 "/a" 和 "/c" 在删除后变为相同文件夹,但这两个文件夹不会被删除,因为删除只会进行一次,且它们没有在删除前被标记。
+  输入:paths =
+  [["a"],["c"],["a","b"],["c","b"],["a","b","x"],["a","b","x","y"],["w"],["w","y"]]
+  输出:[["c"],["c","b"],["a"],["a","b"]]
+  解释:文件结构如上所示。 文件夹 "/a/b/x" 和
+  "/w"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "y"
+  的空文件夹。 注意,文件夹 "/a" 和 "/c"
+  在删除后变为相同文件夹,但这两个文件夹不会被删除,因为删除只会进行一次,且它们没有在删除前被标记。
 
-

示例 3:

- +

+ 示例 3: +

+
-输入:paths = [["a","b"],["c","d"],["c"],["a"]]
-输出:[["c"],["c","d"],["a"],["a","b"]]
-解释:文件系统中所有文件夹互不相同。
-注意,返回的数组可以按不同顺序返回文件夹路径,因为题目对顺序没有要求。
+  输入:paths = [["a","b"],["c","d"],["c"],["a"]]
+  输出:[["c"],["c","d"],["a"],["a","b"]]
+  解释:文件系统中所有文件夹互不相同。
+  注意,返回的数组可以按不同顺序返回文件夹路径,因为题目对顺序没有要求。
 
-

示例 4:

- +

+ 示例 4: +

+
-输入:paths = [["a"],["a","x"],["a","x","y"],["a","z"],["b"],["b","x"],["b","x","y"],["b","z"]]
-输出:[]
-解释:文件结构如上所示。
-文件夹 "/a/x" 和 "/b/x"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "y" 的空文件夹。
-文件夹 "/a" 和 "/b"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含一个名为 "z" 的空文件夹以及上面提到的文件夹 "x" 。
+  输入:paths =
+  [["a"],["a","x"],["a","x","y"],["a","z"],["b"],["b","x"],["b","x","y"],["b","z"]]
+  输出:[]
+  解释:文件结构如上所示。 文件夹 "/a/x" 和
+  "/b/x"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含名为 "y"
+  的空文件夹。 文件夹 "/a" 和
+  "/b"(以及它们的子文件夹)都会被标记为待删除,因为它们都包含一个名为 "z"
+  的空文件夹以及上面提到的文件夹 "x" 。
 
-

示例 5:

- +

+ 示例 5: +

+
-输入:paths = [["a"],["a","x"],["a","x","y"],["a","z"],["b"],["b","x"],["b","x","y"],["b","z"],["b","w"]]
-输出:[["b"],["b","w"],["b","z"],["a"],["a","z"]]
-解释:本例与上例的结构基本相同,除了新增 "/b/w" 文件夹。
-文件夹 "/a/x" 和 "/b/x" 仍然会被标记,但 "/a" 和 "/b" 不再被标记,因为 "/b" 中有名为 "w" 的空文件夹而 "/a" 没有。
-注意,"/a/z" 和 "/b/z" 不会被标记,因为相同子文件夹的集合必须是非空集合,但这两个文件夹都是空的。
+  输入:paths =
+  [["a"],["a","x"],["a","x","y"],["a","z"],["b"],["b","x"],["b","x","y"],["b","z"],["b","w"]]
+  输出:[["b"],["b","w"],["b","z"],["a"],["a","z"]]
+  解释:本例与上例的结构基本相同,除了新增 "/b/w" 文件夹。
+  文件夹 "/a/x" 和 "/b/x" 仍然会被标记,但 "/a" 和 "/b" 不再被标记,因为 "/b"
+  中有名为 "w" 的空文件夹而 "/a" 没有。 注意,"/a/z" 和 "/b/z"
+  不会被标记,因为相同子文件夹的集合必须是非空集合,但这两个文件夹都是空的。
 

 

-

提示:

+

+ 提示: +

@@ -129,150 +207,256 @@ tags: #### Python3 ```python -class TrieNode: + +class Trie: + serial: str = "" + children: dict + def __init__(self): - self.children = collections.defaultdict(TrieNode) - self.key = "" - self.deleted = False + self.children = dict() class Solution: def deleteDuplicateFolder(self, paths: List[List[str]]) -> List[List[str]]: - root = TrieNode() - + root = Trie() for path in paths: - current = root - for folder in path: - current = current.children[folder] - current.key = folder - - seen = collections.defaultdict(list) - - def dfs(node): + cur = root + for node in path: + if node not in cur.children: + cur.children[node] = Trie() + cur = cur.children[node] + freq = Counter() + def construct(node: Trie) -> None: if not node.children: - return "" - keys = [] - for key, child in node.children.items(): - serialized = dfs(child) - keys.append(f"{key}({serialized})") - keys.sort() - serialized = "".join(keys) - if len(seen[serialized]) > 0: - for duplicate in seen[serialized]: - duplicate.deleted = True - node.deleted = True - seen[serialized].append(node) - return serialized - - dfs(root) - - result = [] - path = [] - - def collect(node): - if node.deleted: + return + v = list() + for folder, child in node.children.items(): + construct(child) + v.append(folder + "(" + child.serial + ")") + v.sort() + node.serial = "".join(v) + freq[node.serial] += 1 + construct(root) + ans = list() + path = list() + def operate(node: Trie) -> None: + if freq[node.serial] > 1: return if path: - result.append(path.copy()) - for key, child in node.children.items(): - path.append(key) - collect(child) + ans.append(path[:]) + for folder, child in node.children.items(): + path.append(folder) + operate(child) path.pop() + operate(root) + return ans - collect(root) - return result ``` #### Java ```java -``` +class Solution { -#### C++ + class Trie { -```cpp - -``` - -#### Go - -```go -type TrieNode struct { - children map[string]*TrieNode - key string - deleted bool -} + String serial; + Map children = new HashMap<>(); + } -func deleteDuplicateFolder(paths [][]string) [][]string { - root := &TrieNode{children: make(map[string]*TrieNode)} - - for _, path := range paths { - current := root - for _, folder := range path { - if _, ok := current.children[folder]; !ok { - current.children[folder] = &TrieNode{ - children: make(map[string]*TrieNode), - key: folder, - } + public List> deleteDuplicateFolder(List> paths) { + Trie root = new Trie(); + for (List path : paths) { + Trie cur = root; + for (String node : path) { + cur.children.putIfAbsent(node, new Trie()); + cur = cur.children.get(node); } - current = current.children[folder] } + + Map freq = new HashMap<>(); + construct(root, freq); + List> ans = new ArrayList<>(); + List path = new ArrayList<>(); + operate(root, freq, path, ans); + return ans; } - seen := make(map[string]*TrieNode) - var dfs func(*TrieNode) string - dfs = func(node *TrieNode) string { - if node == nil || len(node.children) == 0 { - return "" - } + private void construct(Trie node, Map freq) { + if (node.children.isEmpty()) return; - var keys []string - for key, child := range node.children { - serialized := dfs(child) - keys = append(keys, key+"("+serialized+")") - } - sort.Strings(keys) - serialized := strings.Join(keys, "") - - if existing, ok := seen[serialized]; ok { - existing.deleted = true - node.deleted = true - } else { - seen[serialized] = node + List v = new ArrayList<>(); + for (Map.Entry entry : node.children.entrySet()) { + construct(entry.getValue(), freq); + v.add(entry.getKey() + "(" + entry.getValue().serial + ")"); } - return serialized + Collections.sort(v); + StringBuilder sb = new StringBuilder(); + for (String s : v) { + sb.append(s); + } + node.serial = sb.toString(); + freq.put(node.serial, freq.getOrDefault(node.serial, 0) + 1); } - dfs(root) - - var result [][]string - var path []string - var collect func(*TrieNode) - collect = func(node *TrieNode) { - if node.deleted { - return + + private void operate( + Trie node, + Map freq, + List path, + List> ans + ) { + if (freq.getOrDefault(node.serial, 0) > 1) return; + + if (!path.isEmpty()) { + ans.add(new ArrayList<>(path)); } - if len(path) > 0 { - newPath := make([]string, len(path)) - copy(newPath, path) - result = append(result, newPath) + + for (Map.Entry entry : node.children.entrySet()) { + path.add(entry.getKey()); + operate(entry.getValue(), freq, path, ans); + path.remove(path.size() - 1); } - for key, child := range node.children { - path = append(path, key) - collect(child) - path = path[:len(path)-1] + } +} + +``` + +#### C++ + +```cpp + +struct Trie { + string serial; + unordered_map children; +}; + +class Solution { +public: + vector> deleteDuplicateFolder( + vector>& paths) { + Trie* root = new Trie(); + + for (const vector& path : paths) { + Trie* cur = root; + for (const string& node : path) { + if (!cur->children.count(node)) { + cur->children[node] = new Trie(); + } + cur = cur->children[node]; + } } + unordered_map freq; + function construct = [&](Trie* node) { + if (node->children.empty()) { + return; + } + + vector v; + for (const auto& [folder, child] : node->children) { + construct(child); + v.push_back(folder + "(" + child->serial + ")"); + } + sort(v.begin(), v.end()); + for (string& s : v) { + node->serial += move(s); + } + ++freq[node->serial]; + }; + + construct(root); + + vector> ans; + vector path; + + function operate = [&](Trie* node) { + if (freq[node->serial] > 1) { + return; + } + if (!path.empty()) { + ans.push_back(path); + } + for (const auto& [folder, child] : node->children) { + path.push_back(folder); + operate(child); + path.pop_back(); + } + }; + + operate(root); + return ans; } - collect(root) +}; + +``` + +#### Go + +```go - return result +type Trie struct { + serial string + children map[string]*Trie } +func deleteDuplicateFolder(paths [][]string) [][]string { + root := &Trie{children: make(map[string]*Trie)} + for _, path := range paths { + cur := root + for _, node := range path { + if _, ok := cur.children[node]; !ok { + cur.children[node] = &Trie{children: make(map[string]*Trie)} + } + cur = cur.children[node] + } + } + + freq := make(map[string]int) + var construct func(*Trie) + construct = func(node *Trie) { + if len(node.children) == 0 { + return + } + v := make([]string, 0, len(node.children)) + for folder, child := range node.children { + construct(child) + v = append(v, folder+"("+child.serial+")") + } + sort.Strings(v) + node.serial = strings.Join(v, "") + freq[node.serial]++ + } + construct(root) + + ans := make([][]string, 0) + path := make([]string, 0) + var operate func(*Trie) + operate = func(node *Trie) { + if freq[node.serial] > 1 { + return + } + if len(path) > 0 { + tmp := make([]string, len(path)) + copy(tmp, path) + ans = append(ans, tmp) + } + for folder, child := range node.children { + path = append(path, folder) + operate(child) + path = path[:len(path)-1] + } + } + operate(root) + + return ans +} + + ``` - + \ No newline at end of file diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/README_EN.md b/solution/1900-1999/1948.Delete Duplicate Folders in System/README_EN.md index 18e22554d5601..a46d62426501f 100644 --- a/solution/1900-1999/1948.Delete Duplicate Folders in System/README_EN.md +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/README_EN.md @@ -5,11 +5,11 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/1900-1999/1948.De rating: 2533 source: Weekly Contest 251 Q4 tags: - - Trie - - Array - - Hash Table - - String - - Hash Function + - Trie + - Array + - Hash Table + - String + - Hash Function --- @@ -22,13 +22,32 @@ tags: -

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.

+

+ 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".
  • +
  • + 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.

+

+ 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: @@ -48,51 +67,110 @@ tags:
-

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.

- -

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.

+

+ 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. +

+ +

+ 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:

- +

+ Example 1: +

+
-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".
+  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:

- +

+ Example 2: +

+
-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.
+  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:

- +

+ Example 3: +

+
-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.
+  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.
 

 

-

Constraints:

+

+ Constraints: +

    -
  • 1 <= paths.length <= 2 * 104
  • -
  • 1 <= paths[i].length <= 500
  • -
  • 1 <= paths[i][j].length <= 10
  • -
  • 1 <= sum(paths[i][j].length) <= 2 * 105
  • -
  • path[i][j] consists of lowercase English letters.
  • -
  • No two paths lead to the same folder.
  • -
  • For any folder not at the root level, its parent folder will also be in the input.
  • +
  • + + 1 <= paths.length <= 2 * 104 + +
  • +
  • + 1 <= paths[i].length <= 500 +
  • +
  • + 1 <= paths[i][j].length <= 10 +
  • +
  • + + 1 <= sum(paths[i][j].length) <= 2 * 105 + +
  • +
  • + path[i][j] consists of lowercase English letters. +
  • +
  • No two paths lead to the same folder.
  • +
  • + For any folder not at the root level, its parent folder will also be in the + input. +
@@ -108,146 +186,252 @@ Note that the returned array can be in a different order as the order does not m #### Python3 ```python -class TrieNode: + +class Trie: + serial: str = "" + children: dict + def __init__(self): - self.children = collections.defaultdict(TrieNode) - self.key = "" - self.deleted = False + self.children = dict() class Solution: def deleteDuplicateFolder(self, paths: List[List[str]]) -> List[List[str]]: - root = TrieNode() - + root = Trie() for path in paths: - current = root - for folder in path: - current = current.children[folder] - current.key = folder - - seen = collections.defaultdict(list) - - def dfs(node): + cur = root + for node in path: + if node not in cur.children: + cur.children[node] = Trie() + cur = cur.children[node] + freq = Counter() + def construct(node: Trie) -> None: if not node.children: - return "" - keys = [] - for key, child in node.children.items(): - serialized = dfs(child) - keys.append(f"{key}({serialized})") - keys.sort() - serialized = "".join(keys) - if len(seen[serialized]) > 0: - for duplicate in seen[serialized]: - duplicate.deleted = True - node.deleted = True - seen[serialized].append(node) - return serialized - - dfs(root) - - result = [] - path = [] - - def collect(node): - if node.deleted: + return + v = list() + for folder, child in node.children.items(): + construct(child) + v.append(folder + "(" + child.serial + ")") + v.sort() + node.serial = "".join(v) + freq[node.serial] += 1 + construct(root) + ans = list() + path = list() + def operate(node: Trie) -> None: + if freq[node.serial] > 1: return if path: - result.append(path.copy()) - for key, child in node.children.items(): - path.append(key) - collect(child) + ans.append(path[:]) + for folder, child in node.children.items(): + path.append(folder) + operate(child) path.pop() + operate(root) + return ans - collect(root) - return result ``` #### Java ```java -``` +class Solution { -#### C++ - -```cpp - -``` - -#### Go + class Trie { -```go -type TrieNode struct { - children map[string]*TrieNode - key string - deleted bool -} + String serial; + Map children = new HashMap<>(); + } -func deleteDuplicateFolder(paths [][]string) [][]string { - root := &TrieNode{children: make(map[string]*TrieNode)} - - for _, path := range paths { - current := root - for _, folder := range path { - if _, ok := current.children[folder]; !ok { - current.children[folder] = &TrieNode{ - children: make(map[string]*TrieNode), - key: folder, - } + public List> deleteDuplicateFolder(List> paths) { + Trie root = new Trie(); + for (List path : paths) { + Trie cur = root; + for (String node : path) { + cur.children.putIfAbsent(node, new Trie()); + cur = cur.children.get(node); } - current = current.children[folder] } + + Map freq = new HashMap<>(); + construct(root, freq); + List> ans = new ArrayList<>(); + List path = new ArrayList<>(); + operate(root, freq, path, ans); + return ans; } - seen := make(map[string]*TrieNode) - var dfs func(*TrieNode) string - dfs = func(node *TrieNode) string { - if node == nil || len(node.children) == 0 { - return "" - } + private void construct(Trie node, Map freq) { + if (node.children.isEmpty()) return; - var keys []string - for key, child := range node.children { - serialized := dfs(child) - keys = append(keys, key+"("+serialized+")") - } - sort.Strings(keys) - serialized := strings.Join(keys, "") - - if existing, ok := seen[serialized]; ok { - existing.deleted = true - node.deleted = true - } else { - seen[serialized] = node + List v = new ArrayList<>(); + for (Map.Entry entry : node.children.entrySet()) { + construct(entry.getValue(), freq); + v.add(entry.getKey() + "(" + entry.getValue().serial + ")"); } - return serialized + Collections.sort(v); + StringBuilder sb = new StringBuilder(); + for (String s : v) { + sb.append(s); + } + node.serial = sb.toString(); + freq.put(node.serial, freq.getOrDefault(node.serial, 0) + 1); } - dfs(root) - - var result [][]string - var path []string - var collect func(*TrieNode) - collect = func(node *TrieNode) { - if node.deleted { - return + + private void operate( + Trie node, + Map freq, + List path, + List> ans + ) { + if (freq.getOrDefault(node.serial, 0) > 1) return; + + if (!path.isEmpty()) { + ans.add(new ArrayList<>(path)); } - if len(path) > 0 { - newPath := make([]string, len(path)) - copy(newPath, path) - result = append(result, newPath) + + for (Map.Entry entry : node.children.entrySet()) { + path.add(entry.getKey()); + operate(entry.getValue(), freq, path, ans); + path.remove(path.size() - 1); } - for key, child := range node.children { - path = append(path, key) - collect(child) - path = path[:len(path)-1] + } +} + +``` + +#### C++ + +```cpp + +struct Trie { + string serial; + unordered_map children; +}; + +class Solution { +public: + vector> deleteDuplicateFolder( + vector>& paths) { + Trie* root = new Trie(); + + for (const vector& path : paths) { + Trie* cur = root; + for (const string& node : path) { + if (!cur->children.count(node)) { + cur->children[node] = new Trie(); + } + cur = cur->children[node]; + } } + unordered_map freq; + function construct = [&](Trie* node) { + if (node->children.empty()) { + return; + } + + vector v; + for (const auto& [folder, child] : node->children) { + construct(child); + v.push_back(folder + "(" + child->serial + ")"); + } + sort(v.begin(), v.end()); + for (string& s : v) { + node->serial += move(s); + } + ++freq[node->serial]; + }; + + construct(root); + + vector> ans; + vector path; + + function operate = [&](Trie* node) { + if (freq[node->serial] > 1) { + return; + } + if (!path.empty()) { + ans.push_back(path); + } + for (const auto& [folder, child] : node->children) { + path.push_back(folder); + operate(child); + path.pop_back(); + } + }; + + operate(root); + return ans; } - collect(root) +}; + +``` + +#### Go + +```go - return result +type Trie struct { + serial string + children map[string]*Trie } +func deleteDuplicateFolder(paths [][]string) [][]string { + root := &Trie{children: make(map[string]*Trie)} + for _, path := range paths { + cur := root + for _, node := range path { + if _, ok := cur.children[node]; !ok { + cur.children[node] = &Trie{children: make(map[string]*Trie)} + } + cur = cur.children[node] + } + } + + freq := make(map[string]int) + var construct func(*Trie) + construct = func(node *Trie) { + if len(node.children) == 0 { + return + } + v := make([]string, 0, len(node.children)) + for folder, child := range node.children { + construct(child) + v = append(v, folder+"("+child.serial+")") + } + sort.Strings(v) + node.serial = strings.Join(v, "") + freq[node.serial]++ + } + construct(root) + + ans := make([][]string, 0) + path := make([]string, 0) + var operate func(*Trie) + operate = func(node *Trie) { + if freq[node.serial] > 1 { + return + } + if len(path) > 0 { + tmp := make([]string, len(path)) + copy(tmp, path) + ans = append(ans, tmp) + } + for folder, child := range node.children { + path = append(path, folder) + operate(child) + path = path[:len(path)-1] + } + } + operate(root) + + return ans +} + + ``` diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.cpp b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.cpp new file mode 100644 index 0000000000000..cf6d5ca6ad4b8 --- /dev/null +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.cpp @@ -0,0 +1,61 @@ +struct Trie { + string serial; + unordered_map children; +}; + +class Solution { +public: + vector> deleteDuplicateFolder( + vector>& paths) { + Trie* root = new Trie(); + + for (const vector& path : paths) { + Trie* cur = root; + for (const string& node : path) { + if (!cur->children.count(node)) { + cur->children[node] = new Trie(); + } + cur = cur->children[node]; + } + } + unordered_map freq; + function construct = [&](Trie* node) { + if (node->children.empty()) { + return; + } + + vector v; + for (const auto& [folder, child] : node->children) { + construct(child); + v.push_back(folder + "(" + child->serial + ")"); + } + sort(v.begin(), v.end()); + for (string& s : v) { + node->serial += move(s); + } + ++freq[node->serial]; + }; + + construct(root); + + vector> ans; + vector path; + + function operate = [&](Trie* node) { + if (freq[node->serial] > 1) { + return; + } + if (!path.empty()) { + ans.push_back(path); + } + for (const auto& [folder, child] : node->children) { + path.push_back(folder); + operate(child); + path.pop_back(); + } + }; + + operate(root); + return ans; + } +}; \ No newline at end of file diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.go b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.go new file mode 100644 index 0000000000000..7feb000eb38ed --- /dev/null +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.go @@ -0,0 +1,56 @@ +type Trie struct { + serial string + children map[string]*Trie +} + +func deleteDuplicateFolder(paths [][]string) [][]string { + root := &Trie{children: make(map[string]*Trie)} + for _, path := range paths { + cur := root + for _, node := range path { + if _, ok := cur.children[node]; !ok { + cur.children[node] = &Trie{children: make(map[string]*Trie)} + } + cur = cur.children[node] + } + } + + freq := make(map[string]int) + var construct func(*Trie) + construct = func(node *Trie) { + if len(node.children) == 0 { + return + } + v := make([]string, 0, len(node.children)) + for folder, child := range node.children { + construct(child) + v = append(v, folder+"("+child.serial+")") + } + sort.Strings(v) + node.serial = strings.Join(v, "") + freq[node.serial]++ + } + construct(root) + + ans := make([][]string, 0) + path := make([]string, 0) + var operate func(*Trie) + operate = func(node *Trie) { + if freq[node.serial] > 1 { + return + } + if len(path) > 0 { + tmp := make([]string, len(path)) + copy(tmp, path) + ans = append(ans, tmp) + } + for folder, child := range node.children { + path = append(path, folder) + operate(child) + path = path[:len(path)-1] + } + } + operate(root) + + return ans +} diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.java b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.java new file mode 100644 index 0000000000000..5bed3ae5d3b4b --- /dev/null +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.java @@ -0,0 +1,63 @@ +class Solution { + + class Trie { + + String serial; + Map children = new HashMap<>(); + } + + public List> deleteDuplicateFolder(List> paths) { + Trie root = new Trie(); + for (List path : paths) { + Trie cur = root; + for (String node : path) { + cur.children.putIfAbsent(node, new Trie()); + cur = cur.children.get(node); + } + } + + Map freq = new HashMap<>(); + construct(root, freq); + List> ans = new ArrayList<>(); + List path = new ArrayList<>(); + operate(root, freq, path, ans); + return ans; + } + + private void construct(Trie node, Map freq) { + if (node.children.isEmpty()) return; + + List v = new ArrayList<>(); + for (Map.Entry entry : node.children.entrySet()) { + construct(entry.getValue(), freq); + v.add(entry.getKey() + "(" + entry.getValue().serial + ")"); + } + + Collections.sort(v); + StringBuilder sb = new StringBuilder(); + for (String s : v) { + sb.append(s); + } + node.serial = sb.toString(); + freq.put(node.serial, freq.getOrDefault(node.serial, 0) + 1); + } + + private void operate( + Trie node, + Map freq, + List path, + List> ans + ) { + if (freq.getOrDefault(node.serial, 0) > 1) return; + + if (!path.isEmpty()) { + ans.add(new ArrayList<>(path)); + } + + for (Map.Entry entry : node.children.entrySet()) { + path.add(entry.getKey()); + operate(entry.getValue(), freq, path, ans); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.js b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.js new file mode 100644 index 0000000000000..1beda7a1176a3 --- /dev/null +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.js @@ -0,0 +1,50 @@ +var deleteDuplicateFolder = function (paths) { + class Trie { + constructor() { + this.serial = ''; + this.children = new Map(); + } + } + + const root = new Trie(); + for (const path of paths) { + let cur = root; + for (const node of path) { + if (!cur.children.has(node)) { + cur.children.set(node, new Trie()); + } + cur = cur.children.get(node); + } + } + + const freq = new Map(); + function construct(node) { + if (node.children.size === 0) return; + const v = []; + for (const [folder, child] of node.children) { + construct(child); + v.push(`${folder}(${child.serial})`); + } + v.sort(); + node.serial = v.join(''); + freq.set(node.serial, (freq.get(node.serial) || 0) + 1); + } + construct(root); + + const ans = []; + const path = []; + function operate(node) { + if ((freq.get(node.serial) || 0) > 1) return; + if (path.length > 0) { + ans.push([...path]); + } + for (const [folder, child] of node.children) { + path.push(folder); + operate(child); + path.pop(); + } + } + operate(root); + + return ans; +}; diff --git a/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.py b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.py new file mode 100644 index 0000000000000..f898e500b6a89 --- /dev/null +++ b/solution/1900-1999/1948.Delete Duplicate Folders in System/solution.py @@ -0,0 +1,42 @@ +class Trie: + serial: str = "" + children: dict + + def __init__(self): + self.children = dict() + + +class Solution: + def deleteDuplicateFolder(self, paths: List[List[str]]) -> List[List[str]]: + root = Trie() + for path in paths: + cur = root + for node in path: + if node not in cur.children: + cur.children[node] = Trie() + cur = cur.children[node] + freq = Counter() + def construct(node: Trie) -> None: + if not node.children: + return + v = list() + for folder, child in node.children.items(): + construct(child) + v.append(folder + "(" + child.serial + ")") + v.sort() + node.serial = "".join(v) + freq[node.serial] += 1 + construct(root) + ans = list() + path = list() + def operate(node: Trie) -> None: + if freq[node.serial] > 1: + return + if path: + ans.append(path[:]) + for folder, child in node.children.items(): + path.append(folder) + operate(child) + path.pop() + operate(root) + return ans \ No newline at end of file diff --git a/solution/3400-3499/3470.Permutations IV/README.md b/solution/3400-3499/3470.Permutations IV/README.md index 81b40ed8af1ec..7b7ec7de99442 100644 --- a/solution/3400-3499/3470.Permutations IV/README.md +++ b/solution/3400-3499/3470.Permutations IV/README.md @@ -114,24 +114,348 @@ tags: ```python +from typing import List +from math import factorial +import heapq + +class Solution: + def permute(self, xxy: int, yyz: int) -> List[int]: + + kasu = {} + nnss = [] + majs = [] + ajwi = heapq.heappush + laoq = [] + + zzp = [i for i in range(1, xxy + 1) if i % 2 == 1] + zzq = [i for i in range(1, xxy + 1) if i % 2 == 0] + + ppp = [] + nxr = None + + for pps in range(xxy): + if pps == 0: + cnd = sorted(zzp + zzq) + else: + cnd = zzp if nxr == 1 else zzq + + fff = False + for cndt in cnd: + if cndt % 2 == 1: + nxt = 0 + noo = len(zzp) - 1 + nee = len(zzq) + else: + nxt = 1 + noo = len(zzp) + nee = len(zzq) - 1 + + llq = noo + nee + if llq == 0: + cnt = 1 + else: + if nxt == 1: + if noo != (llq + 1) // 2 or nee != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + else: + if nee != (llq + 1) // 2 or noo != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + + ajwi(nnss, cnt) + ajwi(majs, llq) + + if cnt >= yyz: + ppp.append(cndt) + if cndt % 2 == 1: + zzp.remove(cndt) + nxr = 0 + else: + zzq.remove(cndt) + nxr = 1 + fff = True + break + else: + yyz -= cnt + + ajwi(laoq, len(ppp)) + + if not fff: + return [] + return ppp + ``` #### Java ```java +import java.util.*; + +class DPHelper { + static final long ok = 10000000000000000L; + long[][][] dp = new long[101][101][2]; + boolean[][][] vis = new boolean[101][101][2]; + + long compute(int o, int e, int p) { + if (o == 0 && e == 0) return 1; + if (vis[o][e][p]) return dp[o][e][p]; + + long r = 0; + if (p == 1) { + if (o == 0) r = 0; + else r = o * compute(o - 1, e, 0); + } else { + if (e == 0) r = 0; + else r = e * compute(o, e - 1, 1); + } + + if (r > ok) r = ok; + vis[o][e][p] = true; + dp[o][e][p] = r; + return r; + } +} + +class SortHelper { + void sortList(ArrayList list) { + Collections.sort(list); + } +} + +class PermutationHelper { + List buildPermutation(int p, ArrayList O, ArrayList E, long k, DPHelper d) { + List ans = new ArrayList<>(); + if (O.size() + E.size() == 0) return ans; + int i = 0; + + if (p == 1) { + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } + } else { + while (i < E.size()) { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = E.get(i); + E.remove(i); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + } + return ans; + } + + List alternateFormation(ArrayList O, ArrayList E, long k, DPHelper d, int n, SortHelper s) { + List ans = new ArrayList<>(); + int tot = O.size() + E.size(); + if (tot % 2 == 1) { + int i = 0; + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + i++; + } + } else { + ArrayList U = new ArrayList<>(); + U.addAll(O); + U.addAll(E); + s.sortList(U); + int i = 0; + while (i < U.size()) { + int x = U.get(i); + if (O.contains(x)) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int idx = O.indexOf(x); + O.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } else { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + } else { + int idx = E.indexOf(x); + E.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + i++; + } + } + return ans; + } +} + +class Solution { + public int[] permute(int n, long k) { + int o = (n + 1) / 2, e = n / 2; + ArrayList O = new ArrayList<>(), E = new ArrayList<>(); + + for (int i = 1; i <= n; i++) { + if (i % 2 == 1) O.add(i); + else E.add(i); + } + + SortHelper s = new SortHelper(); + s.sortList(O); + s.sortList(E); + + DPHelper d = new DPHelper(); + PermutationHelper ph = new PermutationHelper(); + + long tot = 0; + if (n % 2 == 1) tot = d.compute(O.size() - 1, E.size(), 0) * O.size(); + else tot = d.compute(O.size() - 1, E.size(), 0) * O.size() + d.compute(O.size(), E.size() - 1, 1) * E.size(); + + if (k > tot) return new int[0]; + + List res = ph.alternateFormation(O, E, k, d, n, s); + int[] ans = new int[res.size()]; + for (int i = 0; i < res.size(); i++) ans[i] = res.get(i); + + return ans; + } +} + ``` #### C++ ```cpp +class Solution { + long long f[105]; +public: + vector permute(int n, long long k) { + int i,j; + for(i=f[0]=1;i<=n;i++)if(f[i-1]>=k)f[i]=k; + else f[i]=f[i-1]*(i+1>>1); + if(!(n&1))f[n]*=2; + if(f[n] ans(n),a[2]; + for(i=0;i= k { + f[i] = k + } else { + f[i] = f[i-1] * int64((i+1)>>1) + } + } + if n%2 == 0 { + f[n] *= 2 + } + if f[n] < k { + return []int{} + } + k-- + ans := make([]int, n) + a := [2][]int{} + for i := 0; i < n; i++ { + a[i&1] = append(a[i&1], i) + } + + if n%2 == 1 { + ans[0] = int(k/f[n-1]) * 2 + k -= int64(ans[0]/2) * f[n-1] + } else { + ans[0] = int(k / f[n-1]) + k -= int64(ans[0]) * f[n-1] + } + + index := sort.SearchInts(a[ans[0]&1], ans[0]) + a[ans[0]&1] = append(a[ans[0]&1][:index], a[ans[0]&1][index+1:]...) + + for i := 1; i < n; i++ { + if n%2 == 1 { + ans[i] = a[i&1][k/f[n-i-1]] + } else { + ans[i] = a[(ans[0]^i)&1][k/f[n-i-1]] + } + k %= f[n-i-1] + + index = sort.SearchInts(a[ans[i]&1], ans[i]) + a[ans[i]&1] = append(a[ans[i]&1][:index], a[ans[i]&1][index+1:]...) + } + + for i := 0; i < n; i++ { + ans[i]++ + } + return ans +} + ``` diff --git a/solution/3400-3499/3470.Permutations IV/README_EN.md b/solution/3400-3499/3470.Permutations IV/README_EN.md index 611ba7acccf97..dbfc4bc2e0861 100644 --- a/solution/3400-3499/3470.Permutations IV/README_EN.md +++ b/solution/3400-3499/3470.Permutations IV/README_EN.md @@ -111,24 +111,348 @@ tags: ```python +from typing import List +from math import factorial +import heapq + +class Solution: + def permute(self, xxy: int, yyz: int) -> List[int]: + + kasu = {} + nnss = [] + majs = [] + ajwi = heapq.heappush + laoq = [] + + zzp = [i for i in range(1, xxy + 1) if i % 2 == 1] + zzq = [i for i in range(1, xxy + 1) if i % 2 == 0] + + ppp = [] + nxr = None + + for pps in range(xxy): + if pps == 0: + cnd = sorted(zzp + zzq) + else: + cnd = zzp if nxr == 1 else zzq + + fff = False + for cndt in cnd: + if cndt % 2 == 1: + nxt = 0 + noo = len(zzp) - 1 + nee = len(zzq) + else: + nxt = 1 + noo = len(zzp) + nee = len(zzq) - 1 + + llq = noo + nee + if llq == 0: + cnt = 1 + else: + if nxt == 1: + if noo != (llq + 1) // 2 or nee != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + else: + if nee != (llq + 1) // 2 or noo != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + + ajwi(nnss, cnt) + ajwi(majs, llq) + + if cnt >= yyz: + ppp.append(cndt) + if cndt % 2 == 1: + zzp.remove(cndt) + nxr = 0 + else: + zzq.remove(cndt) + nxr = 1 + fff = True + break + else: + yyz -= cnt + + ajwi(laoq, len(ppp)) + + if not fff: + return [] + return ppp + ``` #### Java ```java +import java.util.*; + +class DPHelper { + static final long ok = 10000000000000000L; + long[][][] dp = new long[101][101][2]; + boolean[][][] vis = new boolean[101][101][2]; + + long compute(int o, int e, int p) { + if (o == 0 && e == 0) return 1; + if (vis[o][e][p]) return dp[o][e][p]; + + long r = 0; + if (p == 1) { + if (o == 0) r = 0; + else r = o * compute(o - 1, e, 0); + } else { + if (e == 0) r = 0; + else r = e * compute(o, e - 1, 1); + } + + if (r > ok) r = ok; + vis[o][e][p] = true; + dp[o][e][p] = r; + return r; + } +} + +class SortHelper { + void sortList(ArrayList list) { + Collections.sort(list); + } +} + +class PermutationHelper { + List buildPermutation(int p, ArrayList O, ArrayList E, long k, DPHelper d) { + List ans = new ArrayList<>(); + if (O.size() + E.size() == 0) return ans; + int i = 0; + + if (p == 1) { + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } + } else { + while (i < E.size()) { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = E.get(i); + E.remove(i); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + } + return ans; + } + + List alternateFormation(ArrayList O, ArrayList E, long k, DPHelper d, int n, SortHelper s) { + List ans = new ArrayList<>(); + int tot = O.size() + E.size(); + if (tot % 2 == 1) { + int i = 0; + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + i++; + } + } else { + ArrayList U = new ArrayList<>(); + U.addAll(O); + U.addAll(E); + s.sortList(U); + int i = 0; + while (i < U.size()) { + int x = U.get(i); + if (O.contains(x)) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int idx = O.indexOf(x); + O.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } else { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + } else { + int idx = E.indexOf(x); + E.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + i++; + } + } + return ans; + } +} + +class Solution { + public int[] permute(int n, long k) { + int o = (n + 1) / 2, e = n / 2; + ArrayList O = new ArrayList<>(), E = new ArrayList<>(); + + for (int i = 1; i <= n; i++) { + if (i % 2 == 1) O.add(i); + else E.add(i); + } + + SortHelper s = new SortHelper(); + s.sortList(O); + s.sortList(E); + + DPHelper d = new DPHelper(); + PermutationHelper ph = new PermutationHelper(); + + long tot = 0; + if (n % 2 == 1) tot = d.compute(O.size() - 1, E.size(), 0) * O.size(); + else tot = d.compute(O.size() - 1, E.size(), 0) * O.size() + d.compute(O.size(), E.size() - 1, 1) * E.size(); + + if (k > tot) return new int[0]; + + List res = ph.alternateFormation(O, E, k, d, n, s); + int[] ans = new int[res.size()]; + for (int i = 0; i < res.size(); i++) ans[i] = res.get(i); + + return ans; + } +} + ``` #### C++ ```cpp +class Solution { + long long f[105]; +public: + vector permute(int n, long long k) { + int i,j; + for(i=f[0]=1;i<=n;i++)if(f[i-1]>=k)f[i]=k; + else f[i]=f[i-1]*(i+1>>1); + if(!(n&1))f[n]*=2; + if(f[n] ans(n),a[2]; + for(i=0;i= k { + f[i] = k + } else { + f[i] = f[i-1] * int64((i+1)>>1) + } + } + if n%2 == 0 { + f[n] *= 2 + } + if f[n] < k { + return []int{} + } + k-- + ans := make([]int, n) + a := [2][]int{} + for i := 0; i < n; i++ { + a[i&1] = append(a[i&1], i) + } + + if n%2 == 1 { + ans[0] = int(k/f[n-1]) * 2 + k -= int64(ans[0]/2) * f[n-1] + } else { + ans[0] = int(k / f[n-1]) + k -= int64(ans[0]) * f[n-1] + } + + index := sort.SearchInts(a[ans[0]&1], ans[0]) + a[ans[0]&1] = append(a[ans[0]&1][:index], a[ans[0]&1][index+1:]...) + + for i := 1; i < n; i++ { + if n%2 == 1 { + ans[i] = a[i&1][k/f[n-i-1]] + } else { + ans[i] = a[(ans[0]^i)&1][k/f[n-i-1]] + } + k %= f[n-i-1] + + index = sort.SearchInts(a[ans[i]&1], ans[i]) + a[ans[i]&1] = append(a[ans[i]&1][:index], a[ans[i]&1][index+1:]...) + } + + for i := 0; i < n; i++ { + ans[i]++ + } + return ans +} + ``` diff --git a/solution/3400-3499/3470.Permutations IV/solution.cpp b/solution/3400-3499/3470.Permutations IV/solution.cpp new file mode 100644 index 0000000000000..d4141209a683e --- /dev/null +++ b/solution/3400-3499/3470.Permutations IV/solution.cpp @@ -0,0 +1,40 @@ +class Solution { + long long f[105]; +public: + vector permute(int n, long long k) { + int i,j; + for(i=f[0]=1;i<=n;i++)if(f[i-1]>=k)f[i]=k; + else f[i]=f[i-1]*(i+1>>1); + if(!(n&1))f[n]*=2; + if(f[n] ans(n),a[2]; + for(i=0;i= k { + f[i] = k + } else { + f[i] = f[i-1] * int64((i+1)>>1) + } + } + if n%2 == 0 { + f[n] *= 2 + } + if f[n] < k { + return []int{} + } + k-- + ans := make([]int, n) + a := [2][]int{} + for i := 0; i < n; i++ { + a[i&1] = append(a[i&1], i) + } + + if n%2 == 1 { + ans[0] = int(k/f[n-1]) * 2 + k -= int64(ans[0]/2) * f[n-1] + } else { + ans[0] = int(k / f[n-1]) + k -= int64(ans[0]) * f[n-1] + } + + index := sort.SearchInts(a[ans[0]&1], ans[0]) + a[ans[0]&1] = append(a[ans[0]&1][:index], a[ans[0]&1][index+1:]...) + + for i := 1; i < n; i++ { + if n%2 == 1 { + ans[i] = a[i&1][k/f[n-i-1]] + } else { + ans[i] = a[(ans[0]^i)&1][k/f[n-i-1]] + } + k %= f[n-i-1] + + index = sort.SearchInts(a[ans[i]&1], ans[i]) + a[ans[i]&1] = append(a[ans[i]&1][:index], a[ans[i]&1][index+1:]...) + } + + for i := 0; i < n; i++ { + ans[i]++ + } + return ans +} \ No newline at end of file diff --git a/solution/3400-3499/3470.Permutations IV/solution.java b/solution/3400-3499/3470.Permutations IV/solution.java new file mode 100644 index 0000000000000..5bb48f9c0010d --- /dev/null +++ b/solution/3400-3499/3470.Permutations IV/solution.java @@ -0,0 +1,157 @@ +import java.util.*; + +class DPHelper { + static final long ok = 10000000000000000L; + long[][][] dp = new long[101][101][2]; + boolean[][][] vis = new boolean[101][101][2]; + + long compute(int o, int e, int p) { + if (o == 0 && e == 0) return 1; + if (vis[o][e][p]) return dp[o][e][p]; + + long r = 0; + if (p == 1) { + if (o == 0) r = 0; + else r = o * compute(o - 1, e, 0); + } else { + if (e == 0) r = 0; + else r = e * compute(o, e - 1, 1); + } + + if (r > ok) r = ok; + vis[o][e][p] = true; + dp[o][e][p] = r; + return r; + } +} + +class SortHelper { + void sortList(ArrayList list) { + Collections.sort(list); + } +} + +class PermutationHelper { + List buildPermutation(int p, ArrayList O, ArrayList E, long k, DPHelper d) { + List ans = new ArrayList<>(); + if (O.size() + E.size() == 0) return ans; + int i = 0; + + if (p == 1) { + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } + } else { + while (i < E.size()) { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + i++; + } else { + int x = E.get(i); + E.remove(i); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + } + return ans; + } + + List alternateFormation(ArrayList O, ArrayList E, long k, DPHelper d, int n, SortHelper s) { + List ans = new ArrayList<>(); + int tot = O.size() + E.size(); + if (tot % 2 == 1) { + int i = 0; + while (i < O.size()) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int x = O.get(i); + O.remove(i); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + i++; + } + } else { + ArrayList U = new ArrayList<>(); + U.addAll(O); + U.addAll(E); + s.sortList(U); + int i = 0; + while (i < U.size()) { + int x = U.get(i); + if (O.contains(x)) { + long cnt = d.compute(O.size() - 1, E.size(), 0); + if (k > cnt) { + k -= cnt; + } else { + int idx = O.indexOf(x); + O.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(0, O, E, k, d)); + return ans; + } + } else { + long cnt = d.compute(O.size(), E.size() - 1, 1); + if (k > cnt) { + k -= cnt; + } else { + int idx = E.indexOf(x); + E.remove(idx); + ans.add(x); + ans.addAll(buildPermutation(1, O, E, k, d)); + return ans; + } + } + i++; + } + } + return ans; + } +} + +class Solution { + public int[] permute(int n, long k) { + int o = (n + 1) / 2, e = n / 2; + ArrayList O = new ArrayList<>(), E = new ArrayList<>(); + + for (int i = 1; i <= n; i++) { + if (i % 2 == 1) O.add(i); + else E.add(i); + } + + SortHelper s = new SortHelper(); + s.sortList(O); + s.sortList(E); + + DPHelper d = new DPHelper(); + PermutationHelper ph = new PermutationHelper(); + + long tot = 0; + if (n % 2 == 1) tot = d.compute(O.size() - 1, E.size(), 0) * O.size(); + else tot = d.compute(O.size() - 1, E.size(), 0) * O.size() + d.compute(O.size(), E.size() - 1, 1) * E.size(); + + if (k > tot) return new int[0]; + + List res = ph.alternateFormation(O, E, k, d, n, s); + int[] ans = new int[res.size()]; + for (int i = 0; i < res.size(); i++) ans[i] = res.get(i); + + return ans; + } +} \ No newline at end of file diff --git a/solution/3400-3499/3470.Permutations IV/solution.py b/solution/3400-3499/3470.Permutations IV/solution.py new file mode 100644 index 0000000000000..d1f02ccafb6d6 --- /dev/null +++ b/solution/3400-3499/3470.Permutations IV/solution.py @@ -0,0 +1,72 @@ +from typing import List +from math import factorial +import heapq + +class Solution: + def permute(self, xxy: int, yyz: int) -> List[int]: + + kasu = {} + nnss = [] + majs = [] + ajwi = heapq.heappush + laoq = [] + + zzp = [i for i in range(1, xxy + 1) if i % 2 == 1] + zzq = [i for i in range(1, xxy + 1) if i % 2 == 0] + + ppp = [] + nxr = None + + for pps in range(xxy): + if pps == 0: + cnd = sorted(zzp + zzq) + else: + cnd = zzp if nxr == 1 else zzq + + fff = False + for cndt in cnd: + if cndt % 2 == 1: + nxt = 0 + noo = len(zzp) - 1 + nee = len(zzq) + else: + nxt = 1 + noo = len(zzp) + nee = len(zzq) - 1 + + llq = noo + nee + if llq == 0: + cnt = 1 + else: + if nxt == 1: + if noo != (llq + 1) // 2 or nee != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + else: + if nee != (llq + 1) // 2 or noo != llq // 2: + cnt = 0 + else: + cnt = factorial(noo) * factorial(nee) + + ajwi(nnss, cnt) + ajwi(majs, llq) + + if cnt >= yyz: + ppp.append(cndt) + if cndt % 2 == 1: + zzp.remove(cndt) + nxr = 0 + else: + zzq.remove(cndt) + nxr = 1 + fff = True + break + else: + yyz -= cnt + + ajwi(laoq, len(ppp)) + + if not fff: + return [] + return ppp \ No newline at end of file diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README.md b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README.md index e995fe6b323ae..570505a26c64a 100644 --- a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README.md +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README.md @@ -95,24 +95,173 @@ tags: ```python +class Solution: + def minimumCost(self, nums: List[int], cost: List[int], k: int) -> int: + n = len(nums) + sumN = [0] * (n + 1) + sumC = [0] * (n + 1) + + for i in range(1, n + 1): + sumN[i] = sumN[i - 1] + nums[i - 1] + sumC[i] = sumC[i - 1] + cost[i - 1] + + prevDp = [sys.maxsize] * (n + 1) + prevDp[0] = 0 + + minCost = sys.maxsize + + for m in range(1, n + 1): + currentDp = [sys.maxsize] * (n + 1) + queue = [] + + for r in range(m, n + 1): + l = r - 1 + if l >= m - 1: + x = sumC[l] + y = prevDp[l] + + while len(queue) >= 2: + x1, y1 = queue[-2][0], queue[-2][1] + x2, y2 = queue[-1][0], queue[-1][1] + if (x2 - x1) * (y - y2) <= (x - x2) * (y2 - y1): + queue.pop() + else: + break + queue.append((x, y, l)) + + a = -(sumN[r] + k * m) + + while len(queue) >= 2: + x1, y1 = queue[0][0], queue[0][1] + x2, y2 = queue[1][0], queue[1][1] + if a * x1 + y1 >= a * x2 + y2: + queue.pop(0) + else: + break + + if queue: + x, y = queue[0][0], queue[0][1] + best = a * x + y + currentCost = (sumN[r] + k * m) * sumC[r] + currentCost += best + if currentCost < currentDp[r]: + currentDp[r] = currentCost + + if currentDp[n] < minCost: + minCost = currentDp[n] + prevDp = currentDp + + return minCost + ``` #### Java ```java +class Solution { + public long minimumCost(int[] nums, int[] cost, int k) { + int n = nums.length; + long[] prefixNums = new long[n]; + long[] prefixCosts = new long[n]; + prefixNums[0] = nums[0]; + for (int i = 1; i < n; i++) { + prefixNums[i] = prefixNums[i - 1] + nums[i]; + } + + prefixCosts[0] = cost[0]; + for (int i = 1; i < n; i++) { + prefixCosts[i] = prefixCosts[i - 1] + cost[i]; + } + + Long[][] dp = new Long[n][n]; + long ans = solve(0, 0, k, prefixNums, prefixCosts, dp); + return ans; + } + + public long solve(int start, int end, int k, long[] prefixNums, long[] prefixCosts, Long[][] dp) { + int n = prefixNums.length; + if (end == n) { + if (start == n) return 0; + return Long.MAX_VALUE; + } + + if (dp[start][end] != null) return dp[start][end]; + + long currentNumsSum = prefixNums[end], currentCostSum = prefixCosts[n - 1]; + + if (start != 0){ + currentNumsSum = prefixNums[end] - prefixNums[start - 1]; + currentCostSum = prefixCosts[n - 1] - prefixCosts[start - 1]; + } + + long currentSubarrayCost = (currentNumsSum + k) * currentCostSum; + + long costIfCutHere = currentSubarrayCost + solve(end + 1, end + 1, k, prefixNums, prefixCosts, dp); + long costIfExtend = solve(start, end + 1, k, prefixNums, prefixCosts, dp); + + return dp[start][end] = Math.min(costIfCutHere, costIfExtend); + } +} + ``` #### C++ ```cpp +class Solution { + public: + long long minimumCost(vector& nums, vector& cost, int K) { + int n = nums.size(); + + long long sn[n + 1], sc[n + 1]; + sn[0] = sc[0] = 0; + for (int i = 1; i <= n; i++) { + sn[i] = sn[i - 1] + nums[i - 1]; + sc[i] = sc[i - 1] + cost[i - 1]; + } + + const long long INF = 1e18; + long long f[n + 1]; + for (int i = 0; i <= n; i++) f[i] = INF; + f[0] = 0; + for (int i = 1; i <= n; i++) for (int j = 0; j < i; j++) { + long long t = sn[i] * (sc[i] - sc[j]) + K * (sc[n] - sc[j]); + f[i] = min(f[i], f[j] + t); + } + + return f[n]; + } + }; + ``` #### Go ```go +func minimumCost(a []int, b []int, k int) int64 { + n := len(a) + dp := make([]int, n + 1) + for i := range n { + dp[i] = math.MaxInt / 4 + } + prea := make([]int, n + 1) + preb := make([]int, n + 1) + for i := range n { + prea[i + 1] = prea[i] + a[i] + preb[i + 1] = preb[i] + b[i] + } + for i := n - 1; i >= 0; i-- { + for j := i; j < n; j++ { + tot := (preb[j + 1] - preb[i]) * (prea[j + 1] - prea[0]) + (preb[n] - preb[i]) * k + dp[i] = min(dp[i], tot + dp[j + 1]) + } + } + return int64(dp[0]) +} + ``` diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README_EN.md b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README_EN.md index 130c1edf8b2e5..193b364b06038 100644 --- a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README_EN.md +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/README_EN.md @@ -90,24 +90,173 @@ The minimum total cost possible can be achieved by dividing nums in ```python +class Solution: + def minimumCost(self, nums: List[int], cost: List[int], k: int) -> int: + n = len(nums) + sumN = [0] * (n + 1) + sumC = [0] * (n + 1) + + for i in range(1, n + 1): + sumN[i] = sumN[i - 1] + nums[i - 1] + sumC[i] = sumC[i - 1] + cost[i - 1] + + prevDp = [sys.maxsize] * (n + 1) + prevDp[0] = 0 + + minCost = sys.maxsize + + for m in range(1, n + 1): + currentDp = [sys.maxsize] * (n + 1) + queue = [] + + for r in range(m, n + 1): + l = r - 1 + if l >= m - 1: + x = sumC[l] + y = prevDp[l] + + while len(queue) >= 2: + x1, y1 = queue[-2][0], queue[-2][1] + x2, y2 = queue[-1][0], queue[-1][1] + if (x2 - x1) * (y - y2) <= (x - x2) * (y2 - y1): + queue.pop() + else: + break + queue.append((x, y, l)) + + a = -(sumN[r] + k * m) + + while len(queue) >= 2: + x1, y1 = queue[0][0], queue[0][1] + x2, y2 = queue[1][0], queue[1][1] + if a * x1 + y1 >= a * x2 + y2: + queue.pop(0) + else: + break + + if queue: + x, y = queue[0][0], queue[0][1] + best = a * x + y + currentCost = (sumN[r] + k * m) * sumC[r] + currentCost += best + if currentCost < currentDp[r]: + currentDp[r] = currentCost + + if currentDp[n] < minCost: + minCost = currentDp[n] + prevDp = currentDp + + return minCost + ``` #### Java ```java +class Solution { + public long minimumCost(int[] nums, int[] cost, int k) { + int n = nums.length; + long[] prefixNums = new long[n]; + long[] prefixCosts = new long[n]; + prefixNums[0] = nums[0]; + for (int i = 1; i < n; i++) { + prefixNums[i] = prefixNums[i - 1] + nums[i]; + } + + prefixCosts[0] = cost[0]; + for (int i = 1; i < n; i++) { + prefixCosts[i] = prefixCosts[i - 1] + cost[i]; + } + + Long[][] dp = new Long[n][n]; + long ans = solve(0, 0, k, prefixNums, prefixCosts, dp); + return ans; + } + + public long solve(int start, int end, int k, long[] prefixNums, long[] prefixCosts, Long[][] dp) { + int n = prefixNums.length; + if (end == n) { + if (start == n) return 0; + return Long.MAX_VALUE; + } + + if (dp[start][end] != null) return dp[start][end]; + + long currentNumsSum = prefixNums[end], currentCostSum = prefixCosts[n - 1]; + + if (start != 0){ + currentNumsSum = prefixNums[end] - prefixNums[start - 1]; + currentCostSum = prefixCosts[n - 1] - prefixCosts[start - 1]; + } + + long currentSubarrayCost = (currentNumsSum + k) * currentCostSum; + + long costIfCutHere = currentSubarrayCost + solve(end + 1, end + 1, k, prefixNums, prefixCosts, dp); + long costIfExtend = solve(start, end + 1, k, prefixNums, prefixCosts, dp); + + return dp[start][end] = Math.min(costIfCutHere, costIfExtend); + } +} + ``` #### C++ ```cpp +class Solution { + public: + long long minimumCost(vector& nums, vector& cost, int K) { + int n = nums.size(); + + long long sn[n + 1], sc[n + 1]; + sn[0] = sc[0] = 0; + for (int i = 1; i <= n; i++) { + sn[i] = sn[i - 1] + nums[i - 1]; + sc[i] = sc[i - 1] + cost[i - 1]; + } + + const long long INF = 1e18; + long long f[n + 1]; + for (int i = 0; i <= n; i++) f[i] = INF; + f[0] = 0; + for (int i = 1; i <= n; i++) for (int j = 0; j < i; j++) { + long long t = sn[i] * (sc[i] - sc[j]) + K * (sc[n] - sc[j]); + f[i] = min(f[i], f[j] + t); + } + + return f[n]; + } + }; + ``` #### Go ```go +func minimumCost(a []int, b []int, k int) int64 { + n := len(a) + dp := make([]int, n + 1) + for i := range n { + dp[i] = math.MaxInt / 4 + } + prea := make([]int, n + 1) + preb := make([]int, n + 1) + for i := range n { + prea[i + 1] = prea[i] + a[i] + preb[i + 1] = preb[i] + b[i] + } + for i := n - 1; i >= 0; i-- { + for j := i; j < n; j++ { + tot := (preb[j + 1] - preb[i]) * (prea[j + 1] - prea[0]) + (preb[n] - preb[i]) * k + dp[i] = min(dp[i], tot + dp[j + 1]) + } + } + return int64(dp[0]) +} + ``` diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.cpp b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.cpp new file mode 100644 index 0000000000000..f087b20b76627 --- /dev/null +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.cpp @@ -0,0 +1,24 @@ +class Solution { + public: + long long minimumCost(vector& nums, vector& cost, int K) { + int n = nums.size(); + + long long sn[n + 1], sc[n + 1]; + sn[0] = sc[0] = 0; + for (int i = 1; i <= n; i++) { + sn[i] = sn[i - 1] + nums[i - 1]; + sc[i] = sc[i - 1] + cost[i - 1]; + } + + const long long INF = 1e18; + long long f[n + 1]; + for (int i = 0; i <= n; i++) f[i] = INF; + f[0] = 0; + for (int i = 1; i <= n; i++) for (int j = 0; j < i; j++) { + long long t = sn[i] * (sc[i] - sc[j]) + K * (sc[n] - sc[j]); + f[i] = min(f[i], f[j] + t); + } + + return f[n]; + } + }; \ No newline at end of file diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.go b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.go new file mode 100644 index 0000000000000..811d09609e336 --- /dev/null +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.go @@ -0,0 +1,20 @@ +func minimumCost(a []int, b []int, k int) int64 { + n := len(a) + dp := make([]int, n + 1) + for i := range n { + dp[i] = math.MaxInt / 4 + } + prea := make([]int, n + 1) + preb := make([]int, n + 1) + for i := range n { + prea[i + 1] = prea[i] + a[i] + preb[i + 1] = preb[i] + b[i] + } + for i := n - 1; i >= 0; i-- { + for j := i; j < n; j++ { + tot := (preb[j + 1] - preb[i]) * (prea[j + 1] - prea[0]) + (preb[n] - preb[i]) * k + dp[i] = min(dp[i], tot + dp[j + 1]) + } + } + return int64(dp[0]) +} \ No newline at end of file diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.java b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.java new file mode 100644 index 0000000000000..91244e8f2e551 --- /dev/null +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.java @@ -0,0 +1,44 @@ +class Solution { + public long minimumCost(int[] nums, int[] cost, int k) { + int n = nums.length; + long[] prefixNums = new long[n]; + long[] prefixCosts = new long[n]; + prefixNums[0] = nums[0]; + for (int i = 1; i < n; i++) { + prefixNums[i] = prefixNums[i - 1] + nums[i]; + } + + prefixCosts[0] = cost[0]; + for (int i = 1; i < n; i++) { + prefixCosts[i] = prefixCosts[i - 1] + cost[i]; + } + + Long[][] dp = new Long[n][n]; + long ans = solve(0, 0, k, prefixNums, prefixCosts, dp); + return ans; + } + + public long solve(int start, int end, int k, long[] prefixNums, long[] prefixCosts, Long[][] dp) { + int n = prefixNums.length; + if (end == n) { + if (start == n) return 0; + return Long.MAX_VALUE; + } + + if (dp[start][end] != null) return dp[start][end]; + + long currentNumsSum = prefixNums[end], currentCostSum = prefixCosts[n - 1]; + + if (start != 0){ + currentNumsSum = prefixNums[end] - prefixNums[start - 1]; + currentCostSum = prefixCosts[n - 1] - prefixCosts[start - 1]; + } + + long currentSubarrayCost = (currentNumsSum + k) * currentCostSum; + + long costIfCutHere = currentSubarrayCost + solve(end + 1, end + 1, k, prefixNums, prefixCosts, dp); + long costIfExtend = solve(start, end + 1, k, prefixNums, prefixCosts, dp); + + return dp[start][end] = Math.min(costIfCutHere, costIfExtend); + } +} diff --git a/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.py b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.py new file mode 100644 index 0000000000000..fa90d3facfa1c --- /dev/null +++ b/solution/3500-3599/3500.Minimum Cost to Divide Array Into Subarrays/solution.py @@ -0,0 +1,57 @@ +class Solution: + def minimumCost(self, nums: List[int], cost: List[int], k: int) -> int: + n = len(nums) + sumN = [0] * (n + 1) + sumC = [0] * (n + 1) + + for i in range(1, n + 1): + sumN[i] = sumN[i - 1] + nums[i - 1] + sumC[i] = sumC[i - 1] + cost[i - 1] + + prevDp = [sys.maxsize] * (n + 1) + prevDp[0] = 0 + + minCost = sys.maxsize + + for m in range(1, n + 1): + currentDp = [sys.maxsize] * (n + 1) + queue = [] + + for r in range(m, n + 1): + l = r - 1 + if l >= m - 1: + x = sumC[l] + y = prevDp[l] + + while len(queue) >= 2: + x1, y1 = queue[-2][0], queue[-2][1] + x2, y2 = queue[-1][0], queue[-1][1] + if (x2 - x1) * (y - y2) <= (x - x2) * (y2 - y1): + queue.pop() + else: + break + queue.append((x, y, l)) + + a = -(sumN[r] + k * m) + + while len(queue) >= 2: + x1, y1 = queue[0][0], queue[0][1] + x2, y2 = queue[1][0], queue[1][1] + if a * x1 + y1 >= a * x2 + y2: + queue.pop(0) + else: + break + + if queue: + x, y = queue[0][0], queue[0][1] + best = a * x + y + currentCost = (sumN[r] + k * m) * sumC[r] + currentCost += best + if currentCost < currentDp[r]: + currentDp[r] = currentCost + + if currentDp[n] < minCost: + minCost = currentDp[n] + prevDp = currentDp + + return minCost \ No newline at end of file diff --git a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README.md b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README.md index 34cccad9f3772..755040c932764 100644 --- a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README.md +++ b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README.md @@ -93,18 +93,185 @@ tags: ```python + +from sortedcontainers import SortedList as SL +fmin = lambda a, b: a if a < b else b +class Solution: + def minOperations(self, nums: List[int], l: int, k: int) -> int: + n = len(nums) + lt, gt = SL(), SL() + ls, gs = 0, 0 + def add(x): + nonlocal ls, gs + if not lt or x <= lt[-1]: + lt.add(x) + ls += x + else: + gt.add(x) + gs += x + def remove(x): + nonlocal ls, gs + if x <= lt[-1]: + lt.remove(x) + ls -= x + else: + gt.remove(x) + gs -= x + def adjust(): + nonlocal ls, gs + if len(lt) - len(gt) > 1: + x = lt.pop(-1) + ls -= x + gt.add(x) + gs += x + elif len(gt) - len(lt) > 0: + x = gt.pop(0) + gs -= x + lt.add(x) + ls += x + def getmed(): + return lt[-1] + cost = [0] * (n-l+1) + for i, x in enumerate(nums): + add(x) + adjust() + if i >= l: + remove(nums[i-l]) + adjust() + if i >= l-1: + med = getmed() + cur = gs - med*(len(gt)) + med*len(lt) - ls + cost[i-l+1] = cur + # print(cost) + dp = [[inf] * (k+1) for _ in range(n+1)] + dp[0][0] = 0 + for i in range(1, n+1): + for j in range(k+1): + dp[i][j] = dp[i-1][j] + if i-l >= 0 and k > 0: + dp[i][j] = fmin(dp[i][j], dp[i-l][j-1] + cost[i-l]) + + return dp[n][k] + + ``` #### Java ```java + +class Solution { + + public long minOperations(int[] nums, int x, int k) { + TreeSet set1 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]), set2 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]); + long sum[] = new long[nums.length - x + 1], left = 0, right = 0; + for (int i = 0; i < nums.length; i++) { + set2.add(i); + left += nums[set2.first()]; + right += nums[i] - nums[set2.first()]; + set1.add(set2.pollFirst()); + if (set1.size() > set2.size()) { + left -= nums[set1.last()]; + right += nums[set1.last()]; + set2.add(set1.pollLast()); + } + if (i >= x - 1) { + sum[i - x + 1] = nums[set2.first()] * (set1.size() - set2.size()) - left + right; + left -= set1.remove(i - x + 1) ? nums[i - x + 1] : 0; + right -= set2.remove(i - x + 1) ? nums[i - x + 1] : 0; + } + } + long[][] dp = new long[sum.length + x][k + 1]; + for (int i = 0; i < sum.length + x; i++) { + for (int j = 1; j <= k; j++) { + dp[i][j] = 1000000000000000000L; + } + } + for (int i = 0; i < sum.length; i++) { + for (int j = 1; j <= k; j++) { + dp[i + x][j] = Math.min(dp[i + x - 1][j], sum[i] + dp[i][j - 1]); + } + } + return dp[sum.length + x - 1][k]; + } +} + + ``` #### C++ ```cpp + +class Solution +{ +public: +#define ll long long + ll f[100003][23]; + long long minOperations(vector &a, int x, int k) + { + int n = a.size(); + for (int j = 0; j <= n; ++j) + for (int i = 0; i <= k; ++i) + f[j][i] = 1e18; + f[0][0] = 0; + multiset A, B; + ll as = 0, bs = 0; + for (int i = 0; i < n; ++i) + { + if (B.empty()) + as += a[i], A.insert(a[i]); + else if (A.empty()) + bs += a[i], B.insert(a[i]); + else if (a[i] <= *A.rbegin()) + as += a[i], A.insert(a[i]); + else + bs += a[i], B.insert(a[i]); + if (i - x >= 0) + { + if (A.find(a[i - x]) != A.end()) + { + as -= a[i - x], A.erase(A.find(a[i - x])); + } + else + { + bs -= a[i - x], B.erase(B.find(a[i - x])); + } + } + int sa = A.size(), sb = B.size(); + while (sa - sb >= 2) + { + int o = *A.rbegin(); + as -= o, bs += o; + B.insert(*A.rbegin()), A.erase(prev(A.end())); + --sa, ++sb; + } + while (sa < sb) + { + int o = *B.begin(); + bs -= o, as += o; + A.insert(*B.begin()), B.erase(B.begin()); + ++sa, --sb; + } + // 3 2 + // 3 3 + for (int j = 0; j <= k; ++j) + f[i + 1][j] = f[i][j]; + if (i >= x - 1) + { + ll Z = *A.rbegin(); + ll cost = Z * A.size() - as + bs - Z * B.size(); + for (int j = 1; j <= k; ++j) + f[i + 1][j] = min(f[i + 1][j], f[i - x + 1][j - 1] + cost); + } + } + return f[n][k]; + } +}; + + ``` #### Go diff --git a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README_EN.md b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README_EN.md index 7edceaa6f4d6e..8011bf4ee1ff5 100644 --- a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README_EN.md +++ b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/README_EN.md @@ -88,18 +88,185 @@ tags: ```python + +from sortedcontainers import SortedList as SL +fmin = lambda a, b: a if a < b else b +class Solution: + def minOperations(self, nums: List[int], l: int, k: int) -> int: + n = len(nums) + lt, gt = SL(), SL() + ls, gs = 0, 0 + def add(x): + nonlocal ls, gs + if not lt or x <= lt[-1]: + lt.add(x) + ls += x + else: + gt.add(x) + gs += x + def remove(x): + nonlocal ls, gs + if x <= lt[-1]: + lt.remove(x) + ls -= x + else: + gt.remove(x) + gs -= x + def adjust(): + nonlocal ls, gs + if len(lt) - len(gt) > 1: + x = lt.pop(-1) + ls -= x + gt.add(x) + gs += x + elif len(gt) - len(lt) > 0: + x = gt.pop(0) + gs -= x + lt.add(x) + ls += x + def getmed(): + return lt[-1] + cost = [0] * (n-l+1) + for i, x in enumerate(nums): + add(x) + adjust() + if i >= l: + remove(nums[i-l]) + adjust() + if i >= l-1: + med = getmed() + cur = gs - med*(len(gt)) + med*len(lt) - ls + cost[i-l+1] = cur + # print(cost) + dp = [[inf] * (k+1) for _ in range(n+1)] + dp[0][0] = 0 + for i in range(1, n+1): + for j in range(k+1): + dp[i][j] = dp[i-1][j] + if i-l >= 0 and k > 0: + dp[i][j] = fmin(dp[i][j], dp[i-l][j-1] + cost[i-l]) + + return dp[n][k] + + ``` #### Java ```java + + class Solution { + + public long minOperations(int[] nums, int x, int k) { + TreeSet set1 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]), set2 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]); + long sum[] = new long[nums.length - x + 1], left = 0, right = 0; + for (int i = 0; i < nums.length; i++) { + set2.add(i); + left += nums[set2.first()]; + right += nums[i] - nums[set2.first()]; + set1.add(set2.pollFirst()); + if (set1.size() > set2.size()) { + left -= nums[set1.last()]; + right += nums[set1.last()]; + set2.add(set1.pollLast()); + } + if (i >= x - 1) { + sum[i - x + 1] = nums[set2.first()] * (set1.size() - set2.size()) - left + right; + left -= set1.remove(i - x + 1) ? nums[i - x + 1] : 0; + right -= set2.remove(i - x + 1) ? nums[i - x + 1] : 0; + } + } + long[][] dp = new long[sum.length + x][k + 1]; + for (int i = 0; i < sum.length + x; i++) { + for (int j = 1; j <= k; j++) { + dp[i][j] = 1000000000000000000L; + } + } + for (int i = 0; i < sum.length; i++) { + for (int j = 1; j <= k; j++) { + dp[i + x][j] = Math.min(dp[i + x - 1][j], sum[i] + dp[i][j - 1]); + } + } + return dp[sum.length + x - 1][k]; + } +} + + ``` #### C++ ```cpp + + class Solution +{ +public: +#define ll long long + ll f[100003][23]; + long long minOperations(vector &a, int x, int k) + { + int n = a.size(); + for (int j = 0; j <= n; ++j) + for (int i = 0; i <= k; ++i) + f[j][i] = 1e18; + f[0][0] = 0; + multiset A, B; + ll as = 0, bs = 0; + for (int i = 0; i < n; ++i) + { + if (B.empty()) + as += a[i], A.insert(a[i]); + else if (A.empty()) + bs += a[i], B.insert(a[i]); + else if (a[i] <= *A.rbegin()) + as += a[i], A.insert(a[i]); + else + bs += a[i], B.insert(a[i]); + if (i - x >= 0) + { + if (A.find(a[i - x]) != A.end()) + { + as -= a[i - x], A.erase(A.find(a[i - x])); + } + else + { + bs -= a[i - x], B.erase(B.find(a[i - x])); + } + } + int sa = A.size(), sb = B.size(); + while (sa - sb >= 2) + { + int o = *A.rbegin(); + as -= o, bs += o; + B.insert(*A.rbegin()), A.erase(prev(A.end())); + --sa, ++sb; + } + while (sa < sb) + { + int o = *B.begin(); + bs -= o, as += o; + A.insert(*B.begin()), B.erase(B.begin()); + ++sa, --sb; + } + // 3 2 + // 3 3 + for (int j = 0; j <= k; ++j) + f[i + 1][j] = f[i][j]; + if (i >= x - 1) + { + ll Z = *A.rbegin(); + ll cost = Z * A.size() - as + bs - Z * B.size(); + for (int j = 1; j <= k; ++j) + f[i + 1][j] = min(f[i + 1][j], f[i - x + 1][j - 1] + cost); + } + } + return f[n][k]; + } +}; + + ``` #### Go diff --git a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.cpp b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.cpp new file mode 100644 index 0000000000000..683d7d50dc22b --- /dev/null +++ b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.cpp @@ -0,0 +1,59 @@ +class Solution { +public: +#define ll long long + ll f[100003][23]; + long long minOperations(vector& a, int x, int k) { + int n=a.size(); + for(int j=0; j<=n; ++j) + for(int i=0; i<=k; ++i) + f[j][i]=1e18; + f[0][0]=0; + multiset A,B; + ll as=0,bs=0; + for(int i=0; i=0) + { + if(A.find(a[i-x])!=A.end()) + { + as-=a[i-x],A.erase(A.find(a[i-x])); + } + else + { + bs-=a[i-x],B.erase(B.find(a[i-x])); + } + } + int sa=A.size(),sb=B.size(); + while(sa-sb>=2) + { + int o=*A.rbegin(); + as-=o,bs+=o; + B.insert(*A.rbegin()),A.erase(prev(A.end())); + --sa,++sb; + } + while(sa=x-1) + { + ll Z=*A.rbegin(); + ll cost=Z*A.size()-as+bs-Z*B.size(); + for(int j=1; j<=k; ++j) + f[i+1][j]=min(f[i+1][j],f[i-x+1][j-1]+cost); + } + } + return f[n][k]; + } +}; \ No newline at end of file diff --git a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.java b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.java new file mode 100644 index 0000000000000..8fdc4db56f2cb --- /dev/null +++ b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.java @@ -0,0 +1,35 @@ +class Solution { + + public long minOperations(int[] nums, int x, int k) { + TreeSet set1 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]), set2 = new TreeSet<>((o, p) -> nums[o] == nums[p] ? o - p : nums[o] - nums[p]); + long sum[] = new long[nums.length - x + 1], left = 0, right = 0; + for (int i = 0; i < nums.length; i++) { + set2.add(i); + left += nums[set2.first()]; + right += nums[i] - nums[set2.first()]; + set1.add(set2.pollFirst()); + if (set1.size() > set2.size()) { + left -= nums[set1.last()]; + right += nums[set1.last()]; + set2.add(set1.pollLast()); + } + if (i >= x - 1) { + sum[i - x + 1] = nums[set2.first()] * (set1.size() - set2.size()) - left + right; + left -= set1.remove(i - x + 1) ? nums[i - x + 1] : 0; + right -= set2.remove(i - x + 1) ? nums[i - x + 1] : 0; + } + } + long[][] dp = new long[sum.length + x][k + 1]; + for (int i = 0; i < sum.length + x; i++) { + for (int j = 1; j <= k; j++) { + dp[i][j] = 1000000000000000000L; + } + } + for (int i = 0; i < sum.length; i++) { + for (int j = 1; j <= k; j++) { + dp[i + x][j] = Math.min(dp[i + x - 1][j], sum[i] + dp[i][j - 1]); + } + } + return dp[sum.length + x - 1][k]; + } +} \ No newline at end of file diff --git a/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.py b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.py new file mode 100644 index 0000000000000..491924f6ea47c --- /dev/null +++ b/solution/3500-3599/3505.Minimum Operations to Make Elements Within K Subarrays Equal/solution.py @@ -0,0 +1,58 @@ +from sortedcontainers import SortedList as SL +fmin = lambda a, b: a if a < b else b +class Solution: + def minOperations(self, nums: List[int], l: int, k: int) -> int: + n = len(nums) + lt, gt = SL(), SL() + ls, gs = 0, 0 + def add(x): + nonlocal ls, gs + if not lt or x <= lt[-1]: + lt.add(x) + ls += x + else: + gt.add(x) + gs += x + def remove(x): + nonlocal ls, gs + if x <= lt[-1]: + lt.remove(x) + ls -= x + else: + gt.remove(x) + gs -= x + def adjust(): + nonlocal ls, gs + if len(lt) - len(gt) > 1: + x = lt.pop(-1) + ls -= x + gt.add(x) + gs += x + elif len(gt) - len(lt) > 0: + x = gt.pop(0) + gs -= x + lt.add(x) + ls += x + def getmed(): + return lt[-1] + cost = [0] * (n-l+1) + for i, x in enumerate(nums): + add(x) + adjust() + if i >= l: + remove(nums[i-l]) + adjust() + if i >= l-1: + med = getmed() + cur = gs - med*(len(gt)) + med*len(lt) - ls + cost[i-l+1] = cur + # print(cost) + dp = [[inf] * (k+1) for _ in range(n+1)] + dp[0][0] = 0 + for i in range(1, n+1): + for j in range(k+1): + dp[i][j] = dp[i-1][j] + if i-l >= 0 and k > 0: + dp[i][j] = fmin(dp[i][j], dp[i-l][j-1] + cost[i-l]) + + return dp[n][k] \ No newline at end of file