From 4dd2ce6857c0455cf7ded67bec0eede17b07dbcb Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sat, 13 Jan 2024 09:51:19 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2182 No.2182.Construct String With Repeat Limit --- .../README.md | 106 +++++++++----- .../README_EN.md | 129 ++++++++++++++---- .../Solution.cpp | 52 ++++--- .../Solution.go | 10 +- .../Solution.java | 58 ++++---- .../Solution.py | 43 +++--- .../Solution.ts | 28 ++++ 7 files changed, 289 insertions(+), 137 deletions(-) create mode 100644 solution/2100-2199/2182.Construct String With Repeat Limit/Solution.ts diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/README.md b/solution/2100-2199/2182.Construct String With Repeat Limit/README.md index 221eeb66bf028..9377f23cf0cfd 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/README.md +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/README.md @@ -53,7 +53,11 @@ -**方法一:贪心 + 双指针** +**方法一:贪心** + +我们先用一个长度为 $26$ 的数组 $cnt$ 统计字符串 $s$ 中每个字符出现的次数,然后从大到小枚举字母表的第 $i$ 个字母,每次取出最多 $\min(cnt[i], repeatLimit)$ 个字母 $i$,如果取完后 $cnt[i]$ 还大于 $0$,则继续取字母表中第 $j$ 个字母,其中 $j$ 是最大的满足 $j < i$ 且 $cnt[j] > 0$ 的下标,直到取完所有字母。 + +时间复杂度 $O(n + |\Sigma|)$,空间复杂度 $O(|\Sigma|)$。其中 $n$ 是字符串 $s$ 的长度,而 $\Sigma$ 是字符集,本题中 $|\Sigma| = 26$。 @@ -66,14 +70,15 @@ class Solution: def repeatLimitedString(self, s: str, repeatLimit: int) -> str: cnt = [0] * 26 for c in s: - cnt[ord(c) - ord('a')] += 1 + cnt[ord(c) - ord("a")] += 1 ans = [] + j = 24 for i in range(25, -1, -1): - j = i - 1 + j = min(i - 1, j) while 1: - for _ in range(min(repeatLimit, cnt[i])): - cnt[i] -= 1 - ans.append(chr(ord('a') + i)) + x = min(repeatLimit, cnt[i]) + cnt[i] -= x + ans.append(ascii_lowercase[i] * x) if cnt[i] == 0: break while j >= 0 and cnt[j] == 0: @@ -81,8 +86,8 @@ class Solution: if j < 0: break cnt[j] -= 1 - ans.append(chr(ord('a') + j)) - return ''.join(ans) + ans.append(ascii_lowercase[j]) + return "".join(ans) ``` ### **Java** @@ -93,16 +98,16 @@ class Solution: class Solution { public String repeatLimitedString(String s, int repeatLimit) { int[] cnt = new int[26]; - for (char c : s.toCharArray()) { - cnt[c - 'a']++; + for (int i = 0; i < s.length(); ++i) { + ++cnt[s.charAt(i) - 'a']; } StringBuilder ans = new StringBuilder(); - for (int i = 25; i >= 0; --i) { - int j = i - 1; + for (int i = 25, j = 24; i >= 0; --i) { + j = Math.min(j, i - 1); while (true) { - for (int k = Math.min(repeatLimit, cnt[i]); k > 0; --k) { - cnt[i]--; + for (int k = Math.min(cnt[i], repeatLimit); k > 0; --k) { ans.append((char) ('a' + i)); + --cnt[i]; } if (cnt[i] == 0) { break; @@ -113,8 +118,8 @@ class Solution { if (j < 0) { break; } - cnt[j]--; ans.append((char) ('a' + j)); + --cnt[j]; } } return ans.toString(); @@ -128,21 +133,29 @@ class Solution { class Solution { public: string repeatLimitedString(string s, int repeatLimit) { - vector cnt(26); - for (char& c : s) cnt[c - 'a']++; + int cnt[26]{}; + for (char& c : s) { + ++cnt[c - 'a']; + } string ans; - for (int i = 25; ~i; --i) { - int j = i - 1; - while (true) { + for (int i = 25, j = 24; ~i; --i) { + j = min(j, i - 1); + while (1) { for (int k = min(cnt[i], repeatLimit); k; --k) { - cnt[i]--; - ans.push_back('a' + i); + ans += 'a' + i; + --cnt[i]; + } + if (cnt[i] == 0) { + break; + } + while (j >= 0 && cnt[j] == 0) { + --j; + } + if (j < 0) { + break; } - if (cnt[i] == 0) break; - while (~j && cnt[j] == 0) --j; - if (j < 0) break; - cnt[j]--; - ans.push_back('a' + j); + ans += 'a' + j; + --cnt[j]; } } return ans; @@ -154,17 +167,17 @@ public: ```go func repeatLimitedString(s string, repeatLimit int) string { - cnt := make([]int, 26) + cnt := [26]int{} for _, c := range s { cnt[c-'a']++ } var ans []byte - for i := 25; i >= 0; i-- { - j := i - 1 + for i, j := 25, 24; i >= 0; i-- { + j = min(j, i-1) for { for k := min(cnt[i], repeatLimit); k > 0; k-- { + ans = append(ans, byte(i+'a')) cnt[i]-- - ans = append(ans, 'a'+byte(i)) } if cnt[i] == 0 { break @@ -175,8 +188,8 @@ func repeatLimitedString(s string, repeatLimit int) string { if j < 0 { break } + ans = append(ans, byte(j+'a')) cnt[j]-- - ans = append(ans, 'a'+byte(j)) } } return string(ans) @@ -186,7 +199,34 @@ func repeatLimitedString(s string, repeatLimit int) string { ### **TypeScript** ```ts - +function repeatLimitedString(s: string, repeatLimit: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 97]++; + } + const ans: string[] = []; + for (let i = 25, j = 24; ~i; --i) { + j = Math.min(j, i - 1); + while (true) { + for (let k = Math.min(cnt[i], repeatLimit); k; --k) { + ans.push(String.fromCharCode(97 + i)); + --cnt[i]; + } + if (!cnt[i]) { + break; + } + while (j >= 0 && !cnt[j]) { + --j; + } + if (j < 0) { + break; + } + ans.push(String.fromCharCode(97 + j)); + --cnt[j]; + } + } + return ans.join(''); +} ``` ### **...** diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/README_EN.md b/solution/2100-2199/2182.Construct String With Repeat Limit/README_EN.md index d45843f55a0ab..a1213f52e0cbe 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/README_EN.md +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/README_EN.md @@ -48,6 +48,12 @@ Note that the string "bbabaaa" is lexicographically larger but the let ## Solutions +**Solution 1: Greedy Algorithm** + +First, we use an array $cnt$ of length $26$ to count the number of occurrences of each character in string $s$. Then, we enumerate the $i$th letter of the alphabet in descending order, each time taking out at most $\min(cnt[i], repeatLimit)$ of letter $i$. If after taking them out $cnt[i]$ is still greater than $0$, we continue to take the $j$th letter of the alphabet, where $j$ is the largest index satisfying $j < i$ and $cnt[j] > 0$, until all letters are taken. + +The time complexity is $O(n + |\Sigma|)$, and the space complexity is $O(|\Sigma|)$. Here, $n$ is the length of string $s$, and $\Sigma$ is the character set. In this problem, $|\Sigma| = 26$. + ### **Python3** @@ -57,14 +63,15 @@ class Solution: def repeatLimitedString(self, s: str, repeatLimit: int) -> str: cnt = [0] * 26 for c in s: - cnt[ord(c) - ord('a')] += 1 + cnt[ord(c) - ord("a")] += 1 ans = [] + j = 24 for i in range(25, -1, -1): - j = i - 1 + j = min(i - 1, j) while 1: - for _ in range(min(repeatLimit, cnt[i])): - cnt[i] -= 1 - ans.append(chr(ord('a') + i)) + x = min(repeatLimit, cnt[i]) + cnt[i] -= x + ans.append(ascii_lowercase[i] * x) if cnt[i] == 0: break while j >= 0 and cnt[j] == 0: @@ -72,8 +79,8 @@ class Solution: if j < 0: break cnt[j] -= 1 - ans.append(chr(ord('a') + j)) - return ''.join(ans) + ans.append(ascii_lowercase[j]) + return "".join(ans) ``` ### **Java** @@ -82,16 +89,16 @@ class Solution: class Solution { public String repeatLimitedString(String s, int repeatLimit) { int[] cnt = new int[26]; - for (char c : s.toCharArray()) { - cnt[c - 'a']++; + for (int i = 0; i < s.length(); ++i) { + ++cnt[s.charAt(i) - 'a']; } StringBuilder ans = new StringBuilder(); - for (int i = 25; i >= 0; --i) { - int j = i - 1; + for (int i = 25, j = 24; i >= 0; --i) { + j = Math.min(j, i - 1); while (true) { - for (int k = Math.min(repeatLimit, cnt[i]); k > 0; --k) { - cnt[i]--; + for (int k = Math.min(cnt[i], repeatLimit); k > 0; --k) { ans.append((char) ('a' + i)); + --cnt[i]; } if (cnt[i] == 0) { break; @@ -102,8 +109,8 @@ class Solution { if (j < 0) { break; } - cnt[j]--; ans.append((char) ('a' + j)); + --cnt[j]; } } return ans.toString(); @@ -117,21 +124,29 @@ class Solution { class Solution { public: string repeatLimitedString(string s, int repeatLimit) { - vector cnt(26); - for (char& c : s) cnt[c - 'a']++; + int cnt[26]{}; + for (char& c : s) { + ++cnt[c - 'a']; + } string ans; - for (int i = 25; ~i; --i) { - int j = i - 1; - while (true) { + for (int i = 25, j = 24; ~i; --i) { + j = min(j, i - 1); + while (1) { for (int k = min(cnt[i], repeatLimit); k; --k) { - cnt[i]--; - ans.push_back('a' + i); + ans += 'a' + i; + --cnt[i]; + } + if (cnt[i] == 0) { + break; + } + while (j >= 0 && cnt[j] == 0) { + --j; + } + if (j < 0) { + break; } - if (cnt[i] == 0) break; - while (~j && cnt[j] == 0) --j; - if (j < 0) break; - cnt[j]--; - ans.push_back('a' + j); + ans += 'a' + j; + --cnt[j]; } } return ans; @@ -139,10 +154,70 @@ public: }; ``` +### **Go** + +```go +func repeatLimitedString(s string, repeatLimit int) string { + cnt := [26]int{} + for _, c := range s { + cnt[c-'a']++ + } + var ans []byte + for i, j := 25, 24; i >= 0; i-- { + j = min(j, i-1) + for { + for k := min(cnt[i], repeatLimit); k > 0; k-- { + ans = append(ans, byte(i+'a')) + cnt[i]-- + } + if cnt[i] == 0 { + break + } + for j >= 0 && cnt[j] == 0 { + j-- + } + if j < 0 { + break + } + ans = append(ans, byte(j+'a')) + cnt[j]-- + } + } + return string(ans) +} +``` + ### **TypeScript** ```ts - +function repeatLimitedString(s: string, repeatLimit: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 97]++; + } + const ans: string[] = []; + for (let i = 25, j = 24; ~i; --i) { + j = Math.min(j, i - 1); + while (true) { + for (let k = Math.min(cnt[i], repeatLimit); k; --k) { + ans.push(String.fromCharCode(97 + i)); + --cnt[i]; + } + if (!cnt[i]) { + break; + } + while (j >= 0 && !cnt[j]) { + --j; + } + if (j < 0) { + break; + } + ans.push(String.fromCharCode(97 + j)); + --cnt[j]; + } + } + return ans.join(''); +} ``` ### **...** diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.cpp b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.cpp index aaf4d07b19528..302fa9d22a6dd 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.cpp +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.cpp @@ -1,23 +1,31 @@ -class Solution { -public: - string repeatLimitedString(string s, int repeatLimit) { - vector cnt(26); - for (char& c : s) cnt[c - 'a']++; - string ans; - for (int i = 25; ~i; --i) { - int j = i - 1; - while (true) { - for (int k = min(cnt[i], repeatLimit); k; --k) { - cnt[i]--; - ans.push_back('a' + i); - } - if (cnt[i] == 0) break; - while (~j && cnt[j] == 0) --j; - if (j < 0) break; - cnt[j]--; - ans.push_back('a' + j); - } - } - return ans; - } +class Solution { +public: + string repeatLimitedString(string s, int repeatLimit) { + int cnt[26]{}; + for (char& c : s) { + ++cnt[c - 'a']; + } + string ans; + for (int i = 25, j = 24; ~i; --i) { + j = min(j, i - 1); + while (1) { + for (int k = min(cnt[i], repeatLimit); k; --k) { + ans += 'a' + i; + --cnt[i]; + } + if (cnt[i] == 0) { + break; + } + while (j >= 0 && cnt[j] == 0) { + --j; + } + if (j < 0) { + break; + } + ans += 'a' + j; + --cnt[j]; + } + } + return ans; + } }; \ No newline at end of file diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.go b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.go index cb4ac86c9e1de..aef8e3446092a 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.go +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.go @@ -1,15 +1,15 @@ func repeatLimitedString(s string, repeatLimit int) string { - cnt := make([]int, 26) + cnt := [26]int{} for _, c := range s { cnt[c-'a']++ } var ans []byte - for i := 25; i >= 0; i-- { - j := i - 1 + for i, j := 25, 24; i >= 0; i-- { + j = min(j, i-1) for { for k := min(cnt[i], repeatLimit); k > 0; k-- { + ans = append(ans, byte(i+'a')) cnt[i]-- - ans = append(ans, 'a'+byte(i)) } if cnt[i] == 0 { break @@ -20,8 +20,8 @@ func repeatLimitedString(s string, repeatLimit int) string { if j < 0 { break } + ans = append(ans, byte(j+'a')) cnt[j]-- - ans = append(ans, 'a'+byte(j)) } } return string(ans) diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.java b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.java index 305c350599db7..cfeb5d51f7afd 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.java +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.java @@ -1,30 +1,30 @@ -class Solution { - public String repeatLimitedString(String s, int repeatLimit) { - int[] cnt = new int[26]; - for (char c : s.toCharArray()) { - cnt[c - 'a']++; - } - StringBuilder ans = new StringBuilder(); - for (int i = 25; i >= 0; --i) { - int j = i - 1; - while (true) { - for (int k = Math.min(repeatLimit, cnt[i]); k > 0; --k) { - cnt[i]--; - ans.append((char) ('a' + i)); - } - if (cnt[i] == 0) { - break; - } - while (j >= 0 && cnt[j] == 0) { - --j; - } - if (j < 0) { - break; - } - cnt[j]--; - ans.append((char) ('a' + j)); - } - } - return ans.toString(); - } +class Solution { + public String repeatLimitedString(String s, int repeatLimit) { + int[] cnt = new int[26]; + for (int i = 0; i < s.length(); ++i) { + ++cnt[s.charAt(i) - 'a']; + } + StringBuilder ans = new StringBuilder(); + for (int i = 25, j = 24; i >= 0; --i) { + j = Math.min(j, i - 1); + while (true) { + for (int k = Math.min(cnt[i], repeatLimit); k > 0; --k) { + ans.append((char) ('a' + i)); + --cnt[i]; + } + if (cnt[i] == 0) { + break; + } + while (j >= 0 && cnt[j] == 0) { + --j; + } + if (j < 0) { + break; + } + ans.append((char) ('a' + j)); + --cnt[j]; + } + } + return ans.toString(); + } } \ No newline at end of file diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.py b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.py index fbdf9f49c4b3e..d95c866de91f2 100644 --- a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.py +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.py @@ -1,21 +1,22 @@ -class Solution: - def repeatLimitedString(self, s: str, repeatLimit: int) -> str: - cnt = [0] * 26 - for c in s: - cnt[ord(c) - ord('a')] += 1 - ans = [] - for i in range(25, -1, -1): - j = i - 1 - while 1: - for _ in range(min(repeatLimit, cnt[i])): - cnt[i] -= 1 - ans.append(chr(ord('a') + i)) - if cnt[i] == 0: - break - while j >= 0 and cnt[j] == 0: - j -= 1 - if j < 0: - break - cnt[j] -= 1 - ans.append(chr(ord('a') + j)) - return ''.join(ans) +class Solution: + def repeatLimitedString(self, s: str, repeatLimit: int) -> str: + cnt = [0] * 26 + for c in s: + cnt[ord(c) - ord("a")] += 1 + ans = [] + j = 24 + for i in range(25, -1, -1): + j = min(i - 1, j) + while 1: + x = min(repeatLimit, cnt[i]) + cnt[i] -= x + ans.append(ascii_lowercase[i] * x) + if cnt[i] == 0: + break + while j >= 0 and cnt[j] == 0: + j -= 1 + if j < 0: + break + cnt[j] -= 1 + ans.append(ascii_lowercase[j]) + return "".join(ans) diff --git a/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.ts b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.ts new file mode 100644 index 0000000000000..36624aae18dcb --- /dev/null +++ b/solution/2100-2199/2182.Construct String With Repeat Limit/Solution.ts @@ -0,0 +1,28 @@ +function repeatLimitedString(s: string, repeatLimit: number): string { + const cnt: number[] = Array(26).fill(0); + for (const c of s) { + cnt[c.charCodeAt(0) - 97]++; + } + const ans: string[] = []; + for (let i = 25, j = 24; ~i; --i) { + j = Math.min(j, i - 1); + while (true) { + for (let k = Math.min(cnt[i], repeatLimit); k; --k) { + ans.push(String.fromCharCode(97 + i)); + --cnt[i]; + } + if (!cnt[i]) { + break; + } + while (j >= 0 && !cnt[j]) { + --j; + } + if (j < 0) { + break; + } + ans.push(String.fromCharCode(97 + j)); + --cnt[j]; + } + } + return ans.join(''); +}