diff --git a/solution/3600-3699/3612.Process String with Special Operations I/README.md b/solution/3600-3699/3612.Process String with Special Operations I/README.md index 07ddc74c701ce..bb811dc19670e 100644 --- a/solution/3600-3699/3612.Process String with Special Operations I/README.md +++ b/solution/3600-3699/3612.Process String with Special Operations I/README.md @@ -142,32 +142,128 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3612.Pr -### 方法一 +### 方法一:模拟 + +我们直接模拟题目中的操作即可。我们使用一个列表 $\text{result}$ 来存储当前的结果字符串。遍历输入字符串 $s$ 中的每个字符,根据字符的类型执行相应的操作: + +- 如果字符是小写英文字母,则将其添加到 $\text{result}$ 中。 +- 如果字符是 `*`,则删除 $\text{result}$ 中的最后一个字符(如果存在)。 +- 如果字符是 `#`,则将 $\text{result}$ 复制一遍并追加到其自身后面。 +- 如果字符是 `%`,则反转 $\text{result}$。 + +最后,我们将 $\text{result}$ 转换为字符串并返回。 + +时间复杂度 $O(2^n)$,其中 $n$ 是字符串 $s$ 的长度。最坏情况下,可能会因为 `#` 操作导致 $\text{result}$ 的长度每次翻倍,因此时间复杂度是指数级的。忽略答案的空间消耗,空间复杂度 $O(1)$。 #### Python3 ```python - +class Solution: + def processStr(self, s: str) -> str: + result = [] + for c in s: + if c.isalpha(): + result.append(c) + elif c == "*" and result: + result.pop() + elif c == "#": + result.extend(result) + elif c == "%": + result.reverse() + return "".join(result) ``` #### Java ```java - +class Solution { + public String processStr(String s) { + StringBuilder result = new StringBuilder(); + for (char c : s.toCharArray()) { + if (Character.isLetter(c)) { + result.append(c); + } else if (c == '*') { + result.setLength(Math.max(0, result.length() - 1)); + } else if (c == '#') { + result.append(result); + } else if (c == '%') { + result.reverse(); + } + } + return result.toString(); + } +} ``` #### C++ ```cpp - +class Solution { +public: + string processStr(string s) { + string result; + for (char c : s) { + if (isalpha(c)) { + result += c; + } else if (c == '*') { + if (!result.empty()) { + result.pop_back(); + } + } else if (c == '#') { + result += result; + } else if (c == '%') { + ranges::reverse(result); + } + } + return result; + } +}; ``` #### Go ```go +func processStr(s string) string { + var result []rune + for _, c := range s { + if unicode.IsLetter(c) { + result = append(result, c) + } else if c == '*' { + if len(result) > 0 { + result = result[:len(result)-1] + } + } else if c == '#' { + result = append(result, result...) + } else if c == '%' { + slices.Reverse(result) + } + } + return string(result) +} +``` +#### TypeScript + +```ts +function processStr(s: string): string { + const result: string[] = []; + for (const c of s) { + if (/[a-zA-Z]/.test(c)) { + result.push(c); + } else if (c === '*') { + if (result.length > 0) { + result.pop(); + } + } else if (c === '#') { + result.push(...result); + } else if (c === '%') { + result.reverse(); + } + } + return result.join(''); +} ``` diff --git a/solution/3600-3699/3612.Process String with Special Operations I/README_EN.md b/solution/3600-3699/3612.Process String with Special Operations I/README_EN.md index 1012ea8480ef7..f605677db4b72 100644 --- a/solution/3600-3699/3612.Process String with Special Operations I/README_EN.md +++ b/solution/3600-3699/3612.Process String with Special Operations I/README_EN.md @@ -140,32 +140,128 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3612.Pr -### Solution 1 +### Solution 1: Simulation + +We can directly simulate the operations described in the problem. We use a list $\text{result}$ to store the current result string. For each character in the input string $s$, we perform the corresponding operation based on the character type: + +- If the character is a lowercase English letter, add it to $\text{result}$. +- If the character is `*`, delete the last character in $\text{result}$ (if it exists). +- If the character is `#`, copy $\text{result}$ and append it to itself. +- If the character is `%`, reverse $\text{result}$. + +Finally, we convert $\text{result}$ to a string and return it. + +The time complexity is $O(2^n)$, where $n$ is the length of string $s$. In the worst case, the `#` operation may cause the length of $\text{result}$ to double each time, resulting in exponential time complexity. Ignoring the space consumption of the answer, the space complexity is $O(1)$. #### Python3 ```python - +class Solution: + def processStr(self, s: str) -> str: + result = [] + for c in s: + if c.isalpha(): + result.append(c) + elif c == "*" and result: + result.pop() + elif c == "#": + result.extend(result) + elif c == "%": + result.reverse() + return "".join(result) ``` #### Java ```java - +class Solution { + public String processStr(String s) { + StringBuilder result = new StringBuilder(); + for (char c : s.toCharArray()) { + if (Character.isLetter(c)) { + result.append(c); + } else if (c == '*') { + result.setLength(Math.max(0, result.length() - 1)); + } else if (c == '#') { + result.append(result); + } else if (c == '%') { + result.reverse(); + } + } + return result.toString(); + } +} ``` #### C++ ```cpp - +class Solution { +public: + string processStr(string s) { + string result; + for (char c : s) { + if (isalpha(c)) { + result += c; + } else if (c == '*') { + if (!result.empty()) { + result.pop_back(); + } + } else if (c == '#') { + result += result; + } else if (c == '%') { + ranges::reverse(result); + } + } + return result; + } +}; ``` #### Go ```go +func processStr(s string) string { + var result []rune + for _, c := range s { + if unicode.IsLetter(c) { + result = append(result, c) + } else if c == '*' { + if len(result) > 0 { + result = result[:len(result)-1] + } + } else if c == '#' { + result = append(result, result...) + } else if c == '%' { + slices.Reverse(result) + } + } + return string(result) +} +``` +#### TypeScript + +```ts +function processStr(s: string): string { + const result: string[] = []; + for (const c of s) { + if (/[a-zA-Z]/.test(c)) { + result.push(c); + } else if (c === '*') { + if (result.length > 0) { + result.pop(); + } + } else if (c === '#') { + result.push(...result); + } else if (c === '%') { + result.reverse(); + } + } + return result.join(''); +} ``` diff --git a/solution/3600-3699/3612.Process String with Special Operations I/Solution.cpp b/solution/3600-3699/3612.Process String with Special Operations I/Solution.cpp new file mode 100644 index 0000000000000..7bae1f4d0e5c2 --- /dev/null +++ b/solution/3600-3699/3612.Process String with Special Operations I/Solution.cpp @@ -0,0 +1,20 @@ +class Solution { +public: + string processStr(string s) { + string result; + for (char c : s) { + if (isalpha(c)) { + result += c; + } else if (c == '*') { + if (!result.empty()) { + result.pop_back(); + } + } else if (c == '#') { + result += result; + } else if (c == '%') { + ranges::reverse(result); + } + } + return result; + } +}; \ No newline at end of file diff --git a/solution/3600-3699/3612.Process String with Special Operations I/Solution.go b/solution/3600-3699/3612.Process String with Special Operations I/Solution.go new file mode 100644 index 0000000000000..ca947b8846f6c --- /dev/null +++ b/solution/3600-3699/3612.Process String with Special Operations I/Solution.go @@ -0,0 +1,17 @@ +func processStr(s string) string { + var result []rune + for _, c := range s { + if unicode.IsLetter(c) { + result = append(result, c) + } else if c == '*' { + if len(result) > 0 { + result = result[:len(result)-1] + } + } else if c == '#' { + result = append(result, result...) + } else if c == '%' { + slices.Reverse(result) + } + } + return string(result) +} \ No newline at end of file diff --git a/solution/3600-3699/3612.Process String with Special Operations I/Solution.java b/solution/3600-3699/3612.Process String with Special Operations I/Solution.java new file mode 100644 index 0000000000000..fc383f6e26808 --- /dev/null +++ b/solution/3600-3699/3612.Process String with Special Operations I/Solution.java @@ -0,0 +1,17 @@ +class Solution { + public String processStr(String s) { + StringBuilder result = new StringBuilder(); + for (char c : s.toCharArray()) { + if (Character.isLetter(c)) { + result.append(c); + } else if (c == '*') { + result.setLength(Math.max(0, result.length() - 1)); + } else if (c == '#') { + result.append(result); + } else if (c == '%') { + result.reverse(); + } + } + return result.toString(); + } +} \ No newline at end of file diff --git a/solution/3600-3699/3612.Process String with Special Operations I/Solution.py b/solution/3600-3699/3612.Process String with Special Operations I/Solution.py new file mode 100644 index 0000000000000..631499f429403 --- /dev/null +++ b/solution/3600-3699/3612.Process String with Special Operations I/Solution.py @@ -0,0 +1,13 @@ +class Solution: + def processStr(self, s: str) -> str: + result = [] + for c in s: + if c.isalpha(): + result.append(c) + elif c == "*" and result: + result.pop() + elif c == "#": + result.extend(result) + elif c == "%": + result.reverse() + return "".join(result) diff --git a/solution/3600-3699/3612.Process String with Special Operations I/Solution.ts b/solution/3600-3699/3612.Process String with Special Operations I/Solution.ts new file mode 100644 index 0000000000000..fb4f365f8e1eb --- /dev/null +++ b/solution/3600-3699/3612.Process String with Special Operations I/Solution.ts @@ -0,0 +1,17 @@ +function processStr(s: string): string { + const result: string[] = []; + for (const c of s) { + if (/[a-zA-Z]/.test(c)) { + result.push(c); + } else if (c === '*') { + if (result.length > 0) { + result.pop(); + } + } else if (c === '#') { + result.push(...result); + } else if (c === '%') { + result.reverse(); + } + } + return result.join(''); +} diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/README.md b/solution/3600-3699/3613.Minimize Maximum Component Cost/README.md index beaeff44af1d3..053cac536a4f1 100644 --- a/solution/3600-3699/3613.Minimize Maximum Component Cost/README.md +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/README.md @@ -78,32 +78,184 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3613.Mi -### 方法一 +### 方法一:排序 + 并查集 + +如果 $k = n$,说明所有的边都可以被移除,此时所有的连通分量都是孤立的节点,最大成本为 0。 + +否则,我们可以将所有的边按权值从小到大排序,然后使用并查集来维护连通分量。 + +我们不妨假设初始时所有节点并不联通,初始时每个节点都是一个独立的连通分量。我们从权值最小的边开始,尝试将其加入到当前的连通分量中。如果加入后连通分量的数量已经小于等于 $k$,则说明剩余的边都可以被移除,此时当前边的权值就是我们要找的最大成本,返回该权值即可。否则,我们继续处理下一条边。 + +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是节点的数量。 #### Python3 ```python - +class Solution: + def minCost(self, n: int, edges: List[List[int]], k: int) -> int: + def find(x: int) -> int: + if p[x] != x: + p[x] = find(p[x]) + return p[x] + + if k == n: + return 0 + edges.sort(key=lambda x: x[2]) + cnt = n + p = list(range(n)) + for u, v, w in edges: + pu, pv = find(u), find(v) + if pu != pv: + p[pu] = pv + cnt -= 1 + if cnt <= k: + return w + return 0 ``` #### Java ```java - +class Solution { + private int[] p; + + public int minCost(int n, int[][] edges, int k) { + if (k == n) { + return 0; + } + p = new int[n]; + Arrays.setAll(p, i -> i); + Arrays.sort(edges, Comparator.comparingInt(a -> a[2])); + int cnt = n; + for (var e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } + + private int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int minCost(int n, vector>& edges, int k) { + if (k == n) { + return 0; + } + vector p(n); + ranges::iota(p, 0); + ranges::sort(edges, {}, [](const auto& e) { return e[2]; }); + auto find = [&](this auto&& find, int x) -> int { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + }; + int cnt = n; + for (const auto& e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } +}; ``` #### Go ```go +func minCost(n int, edges [][]int, k int) int { + p := make([]int, n) + for i := range p { + p[i] = i + } + + var find func(int) int + find = func(x int) int { + if p[x] != x { + p[x] = find(p[x]) + } + return p[x] + } + + if k == n { + return 0 + } + + slices.SortFunc(edges, func(a, b []int) int { + return a[2] - b[2] + }) + + cnt := n + for _, e := range edges { + u, v, w := e[0], e[1], e[2] + pu, pv := find(u), find(v) + if pu != pv { + p[pu] = pv + if cnt--; cnt <= k { + return w + } + } + } + + return 0 +} +``` +#### TypeScript + +```ts +function minCost(n: number, edges: number[][], k: number): number { + const p: number[] = Array.from({ length: n }, (_, i) => i); + const find = (x: number): number => { + if (p[x] !== x) { + p[x] = find(p[x]); + } + return p[x]; + }; + + if (k === n) { + return 0; + } + + edges.sort((a, b) => a[2] - b[2]); + let cnt = n; + for (const [u, v, w] of edges) { + const pu = find(u), + pv = find(v); + if (pu !== pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; +} ``` diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/README_EN.md b/solution/3600-3699/3613.Minimize Maximum Component Cost/README_EN.md index f69d66238af7c..0ecce456b455e 100644 --- a/solution/3600-3699/3613.Minimize Maximum Component Cost/README_EN.md +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/README_EN.md @@ -76,32 +76,184 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3613.Mi -### Solution 1 +### Solution 1: Sorting + Union-Find + +If $k = n$, it means all edges can be removed. In this case, all connected components are isolated nodes, and the maximum cost is 0. + +Otherwise, we can sort all edges by weight in ascending order, then use a union-find data structure to maintain connected components. + +We assume that initially all nodes are not connected, with each node being an independent connected component. Starting from the edge with the smallest weight, we try to add it to the current connected components. If the number of connected components becomes less than or equal to $k$ after adding the edge, it means all remaining edges can be removed, and the weight of the current edge is the maximum cost we are looking for. We return this weight. Otherwise, we continue processing the next edge. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$, where $n$ is the number of nodes. #### Python3 ```python - +class Solution: + def minCost(self, n: int, edges: List[List[int]], k: int) -> int: + def find(x: int) -> int: + if p[x] != x: + p[x] = find(p[x]) + return p[x] + + if k == n: + return 0 + edges.sort(key=lambda x: x[2]) + cnt = n + p = list(range(n)) + for u, v, w in edges: + pu, pv = find(u), find(v) + if pu != pv: + p[pu] = pv + cnt -= 1 + if cnt <= k: + return w + return 0 ``` #### Java ```java - +class Solution { + private int[] p; + + public int minCost(int n, int[][] edges, int k) { + if (k == n) { + return 0; + } + p = new int[n]; + Arrays.setAll(p, i -> i); + Arrays.sort(edges, Comparator.comparingInt(a -> a[2])); + int cnt = n; + for (var e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } + + private int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int minCost(int n, vector>& edges, int k) { + if (k == n) { + return 0; + } + vector p(n); + ranges::iota(p, 0); + ranges::sort(edges, {}, [](const auto& e) { return e[2]; }); + auto find = [&](this auto&& find, int x) -> int { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + }; + int cnt = n; + for (const auto& e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } +}; ``` #### Go ```go +func minCost(n int, edges [][]int, k int) int { + p := make([]int, n) + for i := range p { + p[i] = i + } + + var find func(int) int + find = func(x int) int { + if p[x] != x { + p[x] = find(p[x]) + } + return p[x] + } + + if k == n { + return 0 + } + + slices.SortFunc(edges, func(a, b []int) int { + return a[2] - b[2] + }) + + cnt := n + for _, e := range edges { + u, v, w := e[0], e[1], e[2] + pu, pv := find(u), find(v) + if pu != pv { + p[pu] = pv + if cnt--; cnt <= k { + return w + } + } + } + + return 0 +} +``` +#### TypeScript + +```ts +function minCost(n: number, edges: number[][], k: number): number { + const p: number[] = Array.from({ length: n }, (_, i) => i); + const find = (x: number): number => { + if (p[x] !== x) { + p[x] = find(p[x]); + } + return p[x]; + }; + + if (k === n) { + return 0; + } + + edges.sort((a, b) => a[2] - b[2]); + let cnt = n; + for (const [u, v, w] of edges) { + const pu = find(u), + pv = find(v); + if (pu !== pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; +} ``` diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.cpp b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.cpp new file mode 100644 index 0000000000000..c9a02e11d2db3 --- /dev/null +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.cpp @@ -0,0 +1,29 @@ +class Solution { +public: + int minCost(int n, vector>& edges, int k) { + if (k == n) { + return 0; + } + vector p(n); + ranges::iota(p, 0); + ranges::sort(edges, {}, [](const auto& e) { return e[2]; }); + auto find = [&](this auto&& find, int x) -> int { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + }; + int cnt = n; + for (const auto& e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } +}; \ No newline at end of file diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.go b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.go new file mode 100644 index 0000000000000..554ed8c3220af --- /dev/null +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.go @@ -0,0 +1,36 @@ +func minCost(n int, edges [][]int, k int) int { + p := make([]int, n) + for i := range p { + p[i] = i + } + + var find func(int) int + find = func(x int) int { + if p[x] != x { + p[x] = find(p[x]) + } + return p[x] + } + + if k == n { + return 0 + } + + slices.SortFunc(edges, func(a, b []int) int { + return a[2] - b[2] + }) + + cnt := n + for _, e := range edges { + u, v, w := e[0], e[1], e[2] + pu, pv := find(u), find(v) + if pu != pv { + p[pu] = pv + if cnt--; cnt <= k { + return w + } + } + } + + return 0 +} \ No newline at end of file diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.java b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.java new file mode 100644 index 0000000000000..217da449d90c1 --- /dev/null +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.java @@ -0,0 +1,31 @@ +class Solution { + private int[] p; + + public int minCost(int n, int[][] edges, int k) { + if (k == n) { + return 0; + } + p = new int[n]; + Arrays.setAll(p, i -> i); + Arrays.sort(edges, Comparator.comparingInt(a -> a[2])); + int cnt = n; + for (var e : edges) { + int u = e[0], v = e[1], w = e[2]; + int pu = find(u), pv = find(v); + if (pu != pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; + } + + private int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } +} \ No newline at end of file diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.py b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.py new file mode 100644 index 0000000000000..a889bd3a65e37 --- /dev/null +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.py @@ -0,0 +1,20 @@ +class Solution: + def minCost(self, n: int, edges: List[List[int]], k: int) -> int: + def find(x: int) -> int: + if p[x] != x: + p[x] = find(p[x]) + return p[x] + + if k == n: + return 0 + edges.sort(key=lambda x: x[2]) + cnt = n + p = list(range(n)) + for u, v, w in edges: + pu, pv = find(u), find(v) + if pu != pv: + p[pu] = pv + cnt -= 1 + if cnt <= k: + return w + return 0 diff --git a/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.ts b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.ts new file mode 100644 index 0000000000000..aa05e2420b383 --- /dev/null +++ b/solution/3600-3699/3613.Minimize Maximum Component Cost/Solution.ts @@ -0,0 +1,27 @@ +function minCost(n: number, edges: number[][], k: number): number { + const p: number[] = Array.from({ length: n }, (_, i) => i); + const find = (x: number): number => { + if (p[x] !== x) { + p[x] = find(p[x]); + } + return p[x]; + }; + + if (k === n) { + return 0; + } + + edges.sort((a, b) => a[2] - b[2]); + let cnt = n; + for (const [u, v, w] of edges) { + const pu = find(u), + pv = find(v); + if (pu !== pv) { + p[pu] = pv; + if (--cnt <= k) { + return w; + } + } + } + return 0; +}