diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README.md b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README.md index 769aa01176013..6638a4ebf040c 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README.md +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README.md @@ -88,7 +88,22 @@ tags: -### 方法一:记忆化搜索 +### 方法一:前缀和 + 记忆化搜索 + +我们用一个数组 $\textit{nums}$ 记录每个单词的长度,数组的长度记为 $n$。然后我们定义一个长度为 $n + 1$ 的前缀和数组 $\textit{s}$,其中 $\textit{s}[i]$ 表示前 $i$ 个单词的长度之和。 + +接下来,我们设计一个函数 $\textit{dfs}(i)$,表示从第 $i$ 个单词开始分隔句子的最小成本。那么答案为 $\textit{dfs}(0)$。 + +函数 $\textit{dfs}(i)$ 的执行过程如下: + +- 如果从第 $i$ 个单词开始到最后一个单词的长度之和加上单词之间的空格数小于等于 $k$,那么这些单词可以放在最后一行,成本为 $0$。 +- 否则,我们枚举下一个开始分隔的单词的位置 $j$,使得从第 $i$ 个单词到第 $j-1$ 个单词的长度之和加上单词之间的空格数小于等于 $k$。那么 $\textit{dfs}(j)$ 表示从第 $j$ 个单词开始分隔句子的最小成本,而 $(k - m)^2$ 表示将第 $i$ 个单词到第 $j-1$ 个单词放在一行的成本,其中 $m$ 表示从第 $i$ 个单词到第 $j-1$ 个单词的长度之和加上单词之间的空格数。我们枚举所有的 $j$,取最小值即可。 + +答案即为 $\textit{dfs}(0)$。 + +为了避免重复计算,我们可以使用记忆化搜索。 + +时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为单词的个数。 @@ -98,18 +113,19 @@ tags: class Solution: def minimumCost(self, sentence: str, k: int) -> int: @cache - def dfs(i): - if s[-1] - s[i] + n - i - 1 <= k: + def dfs(i: int) -> int: + if s[n] - s[i] + n - i - 1 <= k: return 0 - ans, j = inf, i + 1 - while j < n and (t := s[j] - s[i] + j - i - 1) <= k: - ans = min(ans, (k - t) ** 2 + dfs(j)) + ans = inf + j = i + 1 + while j < n and (m := s[j] - s[i] + j - i - 1) <= k: + ans = min(ans, dfs(j) + (k - m) ** 2) j += 1 return ans - t = [len(w) for w in sentence.split()] - n = len(t) - s = list(accumulate(t, initial=0)) + nums = [len(s) for s in sentence.split()] + n = len(nums) + s = list(accumulate(nums, initial=0)) return dfs(0) ``` @@ -117,40 +133,36 @@ class Solution: ```java class Solution { - private static final int INF = Integer.MAX_VALUE; - private int[] memo; + private Integer[] f; private int[] s; + private int k; private int n; public int minimumCost(String sentence, int k) { + this.k = k; String[] words = sentence.split(" "); n = words.length; + f = new Integer[n]; s = new int[n + 1]; for (int i = 0; i < n; ++i) { s[i + 1] = s[i] + words[i].length(); } - memo = new int[n]; - Arrays.fill(memo, INF); - return dfs(0, k); + return dfs(0); } - private int dfs(int i, int k) { - if (memo[i] != INF) { - return memo[i]; - } + private int dfs(int i) { if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; return 0; } - int ans = INF; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) { - ans = Math.min(ans, (k - t) * (k - t) + dfs(j, k)); - } + if (f[i] != null) { + return f[i]; + } + int ans = Integer.MAX_VALUE; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) * (k - m)); } - memo[i] = ans; - return ans; + return f[i] = ans; } } ``` @@ -160,34 +172,31 @@ class Solution { ```cpp class Solution { public: - const int inf = INT_MAX; - int n; - int minimumCost(string sentence, int k) { - istringstream is(sentence); - vector words; - string word; - while (is >> word) words.push_back(word); - n = words.size(); - vector s(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + words[i].size(); - vector memo(n, inf); - return dfs(0, k, s, memo); - } - - int dfs(int i, int k, vector& s, vector& memo) { - if (memo[i] != inf) return memo[i]; - if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; - return 0; - } - int ans = inf; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) ans = min(ans, (k - t) * (k - t) + dfs(j, k, s, memo)); + istringstream iss(sentence); + vector s = {0}; + string w; + while (iss >> w) { + s.push_back(s.back() + w.size()); } - memo[i] = ans; - return ans; + int n = s.size() - 1; + int f[n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i) -> int { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] != -1) { + return f[i]; + } + int ans = INT_MAX; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = min(ans, dfs(dfs, j) + (k - m) * (k - m)); + } + return f[i] = ans; + }; + return dfs(dfs, 0); } }; ``` @@ -196,40 +205,63 @@ public: ```go func minimumCost(sentence string, k int) int { - words := strings.Split(sentence, " ") - n := len(words) - inf := math.MaxInt32 - s := make([]int, n+1) - for i, word := range words { - s[i+1] = s[i] + len(word) + s := []int{0} + for _, w := range strings.Split(sentence, " ") { + s = append(s, s[len(s)-1]+len(w)) } - memo := make([]int, n) - for i := range memo { - memo[i] = inf + n := len(s) - 1 + f := make([]int, n) + for i := range f { + f[i] = -1 } var dfs func(int) int dfs = func(i int) int { - if memo[i] != inf { - return memo[i] - } if s[n]-s[i]+n-i-1 <= k { - memo[i] = 0 return 0 } - ans := inf - for j := i + 1; j < n; j++ { - t := s[j] - s[i] + j - i - 1 - if t <= k { - ans = min(ans, (k-t)*(k-t)+dfs(j)) - } + if f[i] != -1 { + return f[i] } - memo[i] = ans + ans := math.MaxInt32 + for j := i + 1; j < n && s[j]-s[i]+j-i-1 <= k; j++ { + m := s[j] - s[i] + j - i - 1 + ans = min(ans, dfs(j)+(k-m)*(k-m)) + } + f[i] = ans return ans } return dfs(0) } ``` +#### TypeScript + +```ts +function minimumCost(sentence: string, k: number): number { + const s: number[] = [0]; + for (const w of sentence.split(' ')) { + s.push(s.at(-1)! + w.length); + } + const n = s.length - 1; + const f: number[] = Array(n).fill(-1); + const dfs = (i: number): number => { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] !== -1) { + return f[i]; + } + let ans = Infinity; + for (let j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + const m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) ** 2); + } + return (f[i] = ans); + }; + return dfs(0); +} +``` + diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README_EN.md b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README_EN.md index d08bc2c2c6035..60ca5691d154a 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README_EN.md +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/README_EN.md @@ -87,7 +87,22 @@ The cost of the last row is not included in the total cost, and since there is o -### Solution 1 +### Solution 1: Prefix Sum + Memoized Search + +We use an array $\textit{nums}$ to record the length of each word, and let the length of the array be $n$. Then we define a prefix sum array $\textit{s}$ of length $n + 1$, where $\textit{s}[i]$ represents the sum of the lengths of the first $i$ words. + +Next, we design a function $\textit{dfs}(i)$, which represents the minimum cost of splitting the sentence starting from the $i$-th word. The answer is $\textit{dfs}(0)$. + +The execution process of the function $\textit{dfs}(i)$ is as follows: + +- If the sum of the lengths of the words from the $i$-th word to the last word plus the number of spaces between the words is less than or equal to $k$, then these words can be placed on the last line, and the cost is $0$. +- Otherwise, we enumerate the position $j$ of the next word to start splitting, such that the sum of the lengths of the words from the $i$-th word to the $(j-1)$-th word plus the number of spaces between the words is less than or equal to $k$. Then $\textit{dfs}(j)$ represents the minimum cost of splitting the sentence starting from the $j$-th word, and $(k - m)^2$ represents the cost of placing the words from the $i$-th word to the $(j-1)$-th word on one line, where $m$ represents the sum of the lengths of the words from the $i$-th word to the $(j-1)$-th word plus the number of spaces between the words. We enumerate all $j$ and take the minimum value. + +The answer is $\textit{dfs}(0)$. + +To avoid repeated calculations, we can use memoized search. + +The time complexity is $O(n^2)$, and the space complexity is $O(n)$. Here, $n$ is the number of words. @@ -97,18 +112,19 @@ The cost of the last row is not included in the total cost, and since there is o class Solution: def minimumCost(self, sentence: str, k: int) -> int: @cache - def dfs(i): - if s[-1] - s[i] + n - i - 1 <= k: + def dfs(i: int) -> int: + if s[n] - s[i] + n - i - 1 <= k: return 0 - ans, j = inf, i + 1 - while j < n and (t := s[j] - s[i] + j - i - 1) <= k: - ans = min(ans, (k - t) ** 2 + dfs(j)) + ans = inf + j = i + 1 + while j < n and (m := s[j] - s[i] + j - i - 1) <= k: + ans = min(ans, dfs(j) + (k - m) ** 2) j += 1 return ans - t = [len(w) for w in sentence.split()] - n = len(t) - s = list(accumulate(t, initial=0)) + nums = [len(s) for s in sentence.split()] + n = len(nums) + s = list(accumulate(nums, initial=0)) return dfs(0) ``` @@ -116,40 +132,36 @@ class Solution: ```java class Solution { - private static final int INF = Integer.MAX_VALUE; - private int[] memo; + private Integer[] f; private int[] s; + private int k; private int n; public int minimumCost(String sentence, int k) { + this.k = k; String[] words = sentence.split(" "); n = words.length; + f = new Integer[n]; s = new int[n + 1]; for (int i = 0; i < n; ++i) { s[i + 1] = s[i] + words[i].length(); } - memo = new int[n]; - Arrays.fill(memo, INF); - return dfs(0, k); + return dfs(0); } - private int dfs(int i, int k) { - if (memo[i] != INF) { - return memo[i]; - } + private int dfs(int i) { if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; return 0; } - int ans = INF; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) { - ans = Math.min(ans, (k - t) * (k - t) + dfs(j, k)); - } + if (f[i] != null) { + return f[i]; + } + int ans = Integer.MAX_VALUE; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) * (k - m)); } - memo[i] = ans; - return ans; + return f[i] = ans; } } ``` @@ -159,34 +171,31 @@ class Solution { ```cpp class Solution { public: - const int inf = INT_MAX; - int n; - int minimumCost(string sentence, int k) { - istringstream is(sentence); - vector words; - string word; - while (is >> word) words.push_back(word); - n = words.size(); - vector s(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + words[i].size(); - vector memo(n, inf); - return dfs(0, k, s, memo); - } - - int dfs(int i, int k, vector& s, vector& memo) { - if (memo[i] != inf) return memo[i]; - if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; - return 0; - } - int ans = inf; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) ans = min(ans, (k - t) * (k - t) + dfs(j, k, s, memo)); + istringstream iss(sentence); + vector s = {0}; + string w; + while (iss >> w) { + s.push_back(s.back() + w.size()); } - memo[i] = ans; - return ans; + int n = s.size() - 1; + int f[n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i) -> int { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] != -1) { + return f[i]; + } + int ans = INT_MAX; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = min(ans, dfs(dfs, j) + (k - m) * (k - m)); + } + return f[i] = ans; + }; + return dfs(dfs, 0); } }; ``` @@ -195,40 +204,63 @@ public: ```go func minimumCost(sentence string, k int) int { - words := strings.Split(sentence, " ") - n := len(words) - inf := math.MaxInt32 - s := make([]int, n+1) - for i, word := range words { - s[i+1] = s[i] + len(word) + s := []int{0} + for _, w := range strings.Split(sentence, " ") { + s = append(s, s[len(s)-1]+len(w)) } - memo := make([]int, n) - for i := range memo { - memo[i] = inf + n := len(s) - 1 + f := make([]int, n) + for i := range f { + f[i] = -1 } var dfs func(int) int dfs = func(i int) int { - if memo[i] != inf { - return memo[i] - } if s[n]-s[i]+n-i-1 <= k { - memo[i] = 0 return 0 } - ans := inf - for j := i + 1; j < n; j++ { - t := s[j] - s[i] + j - i - 1 - if t <= k { - ans = min(ans, (k-t)*(k-t)+dfs(j)) - } + if f[i] != -1 { + return f[i] } - memo[i] = ans + ans := math.MaxInt32 + for j := i + 1; j < n && s[j]-s[i]+j-i-1 <= k; j++ { + m := s[j] - s[i] + j - i - 1 + ans = min(ans, dfs(j)+(k-m)*(k-m)) + } + f[i] = ans return ans } return dfs(0) } ``` +#### TypeScript + +```ts +function minimumCost(sentence: string, k: number): number { + const s: number[] = [0]; + for (const w of sentence.split(' ')) { + s.push(s.at(-1)! + w.length); + } + const n = s.length - 1; + const f: number[] = Array(n).fill(-1); + const dfs = (i: number): number => { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] !== -1) { + return f[i]; + } + let ans = Infinity; + for (let j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + const m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) ** 2); + } + return (f[i] = ans); + }; + return dfs(0); +} +``` + diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.cpp b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.cpp index 54dd9c745a0d0..49ab761d99840 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.cpp +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.cpp @@ -1,32 +1,29 @@ class Solution { public: - const int inf = INT_MAX; - int n; - int minimumCost(string sentence, int k) { - istringstream is(sentence); - vector words; - string word; - while (is >> word) words.push_back(word); - n = words.size(); - vector s(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + words[i].size(); - vector memo(n, inf); - return dfs(0, k, s, memo); - } - - int dfs(int i, int k, vector& s, vector& memo) { - if (memo[i] != inf) return memo[i]; - if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; - return 0; - } - int ans = inf; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) ans = min(ans, (k - t) * (k - t) + dfs(j, k, s, memo)); + istringstream iss(sentence); + vector s = {0}; + string w; + while (iss >> w) { + s.push_back(s.back() + w.size()); } - memo[i] = ans; - return ans; + int n = s.size() - 1; + int f[n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i) -> int { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] != -1) { + return f[i]; + } + int ans = INT_MAX; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = min(ans, dfs(dfs, j) + (k - m) * (k - m)); + } + return f[i] = ans; + }; + return dfs(dfs, 0); } -}; \ No newline at end of file +}; diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.go b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.go index 88054f75bbde6..93061027e8b25 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.go +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.go @@ -1,33 +1,28 @@ func minimumCost(sentence string, k int) int { - words := strings.Split(sentence, " ") - n := len(words) - inf := math.MaxInt32 - s := make([]int, n+1) - for i, word := range words { - s[i+1] = s[i] + len(word) + s := []int{0} + for _, w := range strings.Split(sentence, " ") { + s = append(s, s[len(s)-1]+len(w)) } - memo := make([]int, n) - for i := range memo { - memo[i] = inf + n := len(s) - 1 + f := make([]int, n) + for i := range f { + f[i] = -1 } var dfs func(int) int dfs = func(i int) int { - if memo[i] != inf { - return memo[i] - } if s[n]-s[i]+n-i-1 <= k { - memo[i] = 0 return 0 } - ans := inf - for j := i + 1; j < n; j++ { - t := s[j] - s[i] + j - i - 1 - if t <= k { - ans = min(ans, (k-t)*(k-t)+dfs(j)) - } + if f[i] != -1 { + return f[i] + } + ans := math.MaxInt32 + for j := i + 1; j < n && s[j]-s[i]+j-i-1 <= k; j++ { + m := s[j] - s[i] + j - i - 1 + ans = min(ans, dfs(j)+(k-m)*(k-m)) } - memo[i] = ans + f[i] = ans return ans } return dfs(0) -} \ No newline at end of file +} diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.java b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.java index 144b71888ae7f..e698e9a7b9af5 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.java +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.java @@ -1,37 +1,33 @@ class Solution { - private static final int INF = Integer.MAX_VALUE; - private int[] memo; + private Integer[] f; private int[] s; + private int k; private int n; public int minimumCost(String sentence, int k) { + this.k = k; String[] words = sentence.split(" "); n = words.length; + f = new Integer[n]; s = new int[n + 1]; for (int i = 0; i < n; ++i) { s[i + 1] = s[i] + words[i].length(); } - memo = new int[n]; - Arrays.fill(memo, INF); - return dfs(0, k); + return dfs(0); } - private int dfs(int i, int k) { - if (memo[i] != INF) { - return memo[i]; - } + private int dfs(int i) { if (s[n] - s[i] + n - i - 1 <= k) { - memo[i] = 0; return 0; } - int ans = INF; - for (int j = i + 1; j < n; ++j) { - int t = s[j] - s[i] + j - i - 1; - if (t <= k) { - ans = Math.min(ans, (k - t) * (k - t) + dfs(j, k)); - } + if (f[i] != null) { + return f[i]; + } + int ans = Integer.MAX_VALUE; + for (int j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + int m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) * (k - m)); } - memo[i] = ans; - return ans; + return f[i] = ans; } -} \ No newline at end of file +} diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.py b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.py index 555aee4380312..0d7b0f108f2be 100644 --- a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.py +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.py @@ -1,16 +1,17 @@ class Solution: def minimumCost(self, sentence: str, k: int) -> int: @cache - def dfs(i): - if s[-1] - s[i] + n - i - 1 <= k: + def dfs(i: int) -> int: + if s[n] - s[i] + n - i - 1 <= k: return 0 - ans, j = inf, i + 1 - while j < n and (t := s[j] - s[i] + j - i - 1) <= k: - ans = min(ans, (k - t) ** 2 + dfs(j)) + ans = inf + j = i + 1 + while j < n and (m := s[j] - s[i] + j - i - 1) <= k: + ans = min(ans, dfs(j) + (k - m) ** 2) j += 1 return ans - t = [len(w) for w in sentence.split()] - n = len(t) - s = list(accumulate(t, initial=0)) + nums = [len(s) for s in sentence.split()] + n = len(nums) + s = list(accumulate(nums, initial=0)) return dfs(0) diff --git a/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.ts b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.ts new file mode 100644 index 0000000000000..961dd1d7abd8c --- /dev/null +++ b/solution/2000-2099/2052.Minimum Cost to Separate Sentence Into Rows/Solution.ts @@ -0,0 +1,23 @@ +function minimumCost(sentence: string, k: number): number { + const s: number[] = [0]; + for (const w of sentence.split(' ')) { + s.push(s.at(-1)! + w.length); + } + const n = s.length - 1; + const f: number[] = Array(n).fill(-1); + const dfs = (i: number): number => { + if (s[n] - s[i] + n - i - 1 <= k) { + return 0; + } + if (f[i] !== -1) { + return f[i]; + } + let ans = Infinity; + for (let j = i + 1; j < n && s[j] - s[i] + j - i - 1 <= k; ++j) { + const m = s[j] - s[i] + j - i - 1; + ans = Math.min(ans, dfs(j) + (k - m) ** 2); + } + return (f[i] = ans); + }; + return dfs(0); +} diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/README.md b/solution/2000-2099/2053.Kth Distinct String in an Array/README.md index c3b4767aeec08..9d987e9158b14 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/README.md +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/README.md @@ -72,7 +72,11 @@ arr 中所有字符串都是独一无二的,所以返回第 1 个字符串 "aa -### 方法一 +### 方法一:哈希表 + 计数 + +我们可以用一个哈希表 $\textit{cnt}$ 记录每个字符串出现的次数,然后再遍历一次数组,对于每个字符串,如果它出现的次数为 $1$,那么就将 $k$ 减一,直到 $k$ 减为 $0$,返回当前字符串即可。 + +时间复杂度 $O(L)$,空间复杂度 $O(L)$,其中 $L$ 为数组 $\textit{arr}$ 所有字符串的长度之和。 @@ -81,13 +85,13 @@ arr 中所有字符串都是独一无二的,所以返回第 1 个字符串 "aa ```python class Solution: def kthDistinct(self, arr: List[str], k: int) -> str: - counter = Counter(arr) - for v in arr: - if counter[v] == 1: + cnt = Counter(arr) + for s in arr: + if cnt[s] == 1: k -= 1 if k == 0: - return v - return '' + return s + return "" ``` #### Java @@ -95,16 +99,13 @@ class Solution: ```java class Solution { public String kthDistinct(String[] arr, int k) { - Map counter = new HashMap<>(); - for (String v : arr) { - counter.put(v, counter.getOrDefault(v, 0) + 1); + Map cnt = new HashMap<>(); + for (String s : arr) { + cnt.merge(s, 1, Integer::sum); } - for (String v : arr) { - if (counter.get(v) == 1) { - --k; - if (k == 0) { - return v; - } + for (String s : arr) { + if (cnt.get(s) == 1 && --k == 0) { + return s; } } return ""; @@ -118,12 +119,13 @@ class Solution { class Solution { public: string kthDistinct(vector& arr, int k) { - unordered_map counter; - for (auto& v : arr) ++counter[v]; - for (auto& v : arr) { - if (counter[v] == 1) { - --k; - if (k == 0) return v; + unordered_map cnt; + for (const auto& s : arr) { + ++cnt[s]; + } + for (const auto& s : arr) { + if (cnt[s] == 1 && --k == 0) { + return s; } } return ""; @@ -135,15 +137,15 @@ public: ```go func kthDistinct(arr []string, k int) string { - counter := make(map[string]int) - for _, v := range arr { - counter[v]++ + cnt := map[string]int{} + for _, s := range arr { + cnt[s]++ } - for _, v := range arr { - if counter[v] == 1 { + for _, s := range arr { + if cnt[s] == 1 { k-- if k == 0 { - return v + return s } } } @@ -156,91 +158,65 @@ func kthDistinct(arr []string, k int) string { ```ts function kthDistinct(arr: string[], k: number): string { const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; } ``` -#### JavaScript - -```js -function kthDistinct(arr k) { - const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); - } +#### Rust - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; - } +```rust +use std::collections::HashMap; - return ''; -} -``` - - - - +impl Solution { + pub fn kth_distinct(arr: Vec, mut k: i32) -> String { + let mut cnt = HashMap::new(); - - -### 方法二:哈希表 - - - -#### TypeScript + for s in &arr { + *cnt.entry(s).or_insert(0) += 1; + } -```ts -function kthDistinct(arr: string[], k: number): string { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); - } + for s in &arr { + if *cnt.get(s).unwrap() == 1 { + k -= 1; + if k == 0 { + return s.clone(); + } + } + } - for (const x of distinct) { - if (--k === 0) return x; + "".to_string() } - - return ''; } ``` #### JavaScript ```js -function kthDistinct(arr, k) { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); +/** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ +var kthDistinct = function (arr, k) { + const cnt = new Map(); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const x of distinct) { - if (--k === 0) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; -} +}; ``` diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/README_EN.md b/solution/2000-2099/2053.Kth Distinct String in an Array/README_EN.md index 87e769117b372..898fe906c121b 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/README_EN.md +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/README_EN.md @@ -73,7 +73,11 @@ The only distinct string is "b". Since there are fewer than 3 distinct -### Solution 1: Counting +### Solution 1: Hash Table + Counting + +We can use a hash table $\textit{cnt}$ to record the number of occurrences of each string. Then, we traverse the array once more. For each string, if its occurrence count is $1$, we decrement $k$ by one. When $k$ reaches $0$, we return the current string. + +Time complexity is $O(L)$, and space complexity is $O(L)$, where $L$ is the total length of all strings in the array $\textit{arr}$. @@ -82,13 +86,13 @@ The only distinct string is "b". Since there are fewer than 3 distinct ```python class Solution: def kthDistinct(self, arr: List[str], k: int) -> str: - counter = Counter(arr) - for v in arr: - if counter[v] == 1: + cnt = Counter(arr) + for s in arr: + if cnt[s] == 1: k -= 1 if k == 0: - return v - return '' + return s + return "" ``` #### Java @@ -96,16 +100,13 @@ class Solution: ```java class Solution { public String kthDistinct(String[] arr, int k) { - Map counter = new HashMap<>(); - for (String v : arr) { - counter.put(v, counter.getOrDefault(v, 0) + 1); + Map cnt = new HashMap<>(); + for (String s : arr) { + cnt.merge(s, 1, Integer::sum); } - for (String v : arr) { - if (counter.get(v) == 1) { - --k; - if (k == 0) { - return v; - } + for (String s : arr) { + if (cnt.get(s) == 1 && --k == 0) { + return s; } } return ""; @@ -119,12 +120,13 @@ class Solution { class Solution { public: string kthDistinct(vector& arr, int k) { - unordered_map counter; - for (auto& v : arr) ++counter[v]; - for (auto& v : arr) { - if (counter[v] == 1) { - --k; - if (k == 0) return v; + unordered_map cnt; + for (const auto& s : arr) { + ++cnt[s]; + } + for (const auto& s : arr) { + if (cnt[s] == 1 && --k == 0) { + return s; } } return ""; @@ -136,15 +138,15 @@ public: ```go func kthDistinct(arr []string, k int) string { - counter := make(map[string]int) - for _, v := range arr { - counter[v]++ + cnt := map[string]int{} + for _, s := range arr { + cnt[s]++ } - for _, v := range arr { - if counter[v] == 1 { + for _, s := range arr { + if cnt[s] == 1 { k-- if k == 0 { - return v + return s } } } @@ -157,91 +159,65 @@ func kthDistinct(arr []string, k int) string { ```ts function kthDistinct(arr: string[], k: number): string { const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; } ``` -#### JavaScript - -```js -function kthDistinct(arr k) { - const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); - } +#### Rust - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; - } +```rust +use std::collections::HashMap; - return ''; -} -``` - - - - +impl Solution { + pub fn kth_distinct(arr: Vec, mut k: i32) -> String { + let mut cnt = HashMap::new(); - - -### Solution 2: Hash Set - - - -#### TypeScript + for s in &arr { + *cnt.entry(s).or_insert(0) += 1; + } -```ts -function kthDistinct(arr: string[], k: number): string { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); - } + for s in &arr { + if *cnt.get(s).unwrap() == 1 { + k -= 1; + if k == 0 { + return s.clone(); + } + } + } - for (const x of distinct) { - if (--k === 0) return x; + "".to_string() } - - return ''; } ``` #### JavaScript ```js -function kthDistinct(arr, k) { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); +/** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ +var kthDistinct = function (arr, k) { + const cnt = new Map(); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const x of distinct) { - if (--k === 0) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; -} +}; ``` diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.cpp b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.cpp index b31ef8e13ea43..2cace2549e0de 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.cpp +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.cpp @@ -1,14 +1,15 @@ class Solution { public: string kthDistinct(vector& arr, int k) { - unordered_map counter; - for (auto& v : arr) ++counter[v]; - for (auto& v : arr) { - if (counter[v] == 1) { - --k; - if (k == 0) return v; + unordered_map cnt; + for (const auto& s : arr) { + ++cnt[s]; + } + for (const auto& s : arr) { + if (cnt[s] == 1 && --k == 0) { + return s; } } return ""; } -}; \ No newline at end of file +}; diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.go b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.go index 02116bc2cb0d4..5ba5cfd3c1ff6 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.go +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.go @@ -1,15 +1,15 @@ func kthDistinct(arr []string, k int) string { - counter := make(map[string]int) - for _, v := range arr { - counter[v]++ + cnt := map[string]int{} + for _, s := range arr { + cnt[s]++ } - for _, v := range arr { - if counter[v] == 1 { + for _, s := range arr { + if cnt[s] == 1 { k-- if k == 0 { - return v + return s } } } return "" -} \ No newline at end of file +} diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.java b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.java index ebf7e38bc0072..fd70caa4067ea 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.java +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.java @@ -1,17 +1,14 @@ class Solution { public String kthDistinct(String[] arr, int k) { - Map counter = new HashMap<>(); - for (String v : arr) { - counter.put(v, counter.getOrDefault(v, 0) + 1); + Map cnt = new HashMap<>(); + for (String s : arr) { + cnt.merge(s, 1, Integer::sum); } - for (String v : arr) { - if (counter.get(v) == 1) { - --k; - if (k == 0) { - return v; - } + for (String s : arr) { + if (cnt.get(s) == 1 && --k == 0) { + return s; } } return ""; } -} \ No newline at end of file +} diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.js b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.js index dfd538eba9e50..fa91e3f66587e 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.js +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.js @@ -1,14 +1,17 @@ -function kthDistinct(arr k) { +/** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ +var kthDistinct = function (arr, k) { const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; -} +}; diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.py b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.py index 3949ae806eff8..171e56be193df 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.py +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.py @@ -1,9 +1,9 @@ class Solution: def kthDistinct(self, arr: List[str], k: int) -> str: - counter = Counter(arr) - for v in arr: - if counter[v] == 1: + cnt = Counter(arr) + for s in arr: + if cnt[s] == 1: k -= 1 if k == 0: - return v - return '' + return s + return "" diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.rs b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.rs new file mode 100644 index 0000000000000..fc6885f2802eb --- /dev/null +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; + +impl Solution { + pub fn kth_distinct(arr: Vec, mut k: i32) -> String { + let mut cnt = HashMap::new(); + + for s in &arr { + *cnt.entry(s).or_insert(0) += 1; + } + + for s in &arr { + if *cnt.get(s).unwrap() == 1 { + k -= 1; + if k == 0 { + return s.clone(); + } + } + } + + "".to_string() + } +} diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.ts b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.ts index a86d510f48c60..c9501b49a3fc4 100644 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.ts +++ b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution.ts @@ -1,14 +1,12 @@ function kthDistinct(arr: string[], k: number): string { const cnt = new Map(); - - for (const x of arr) { - cnt.set(x, (cnt.get(x) ?? 0) + 1); + for (const s of arr) { + cnt.set(s, (cnt.get(s) || 0) + 1); } - - for (const [x, c] of cnt) { - if (c === 1) k--; - if (!k) return x; + for (const s of arr) { + if (cnt.get(s) === 1 && --k === 0) { + return s; + } } - return ''; } diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.js b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.js deleted file mode 100644 index ac6ce8b3e0750..0000000000000 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.js +++ /dev/null @@ -1,17 +0,0 @@ -function kthDistinct(arr, k) { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); - } - - for (const x of distinct) { - if (--k === 0) return x; - } - - return ''; -} diff --git a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.ts b/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.ts deleted file mode 100644 index 25879beb54924..0000000000000 --- a/solution/2000-2099/2053.Kth Distinct String in an Array/Solution2.ts +++ /dev/null @@ -1,17 +0,0 @@ -function kthDistinct(arr: string[], k: number): string { - const distinct = new Set(); - const duplicate = new Set(); - - for (const x of arr) { - if (distinct.has(x)) { - distinct.delete(x); - duplicate.add(x); - } else if (!duplicate.has(x)) distinct.add(x); - } - - for (const x of distinct) { - if (--k === 0) return x; - } - - return ''; -}