From 848e5e9a7e06eaaf5b3cc9879bc5e47e77449743 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 12 Jul 2024 20:04:19 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1717 No.1717.Maximum Score From Removing Substrings --- .../README.md | 215 ++++++++++-------- .../README_EN.md | 215 ++++++++++-------- .../Solution.cpp | 43 ++-- .../Solution.go | 45 ++-- .../Solution.java | 44 ++-- .../Solution.py | 31 ++- .../Solution.ts | 27 +++ 7 files changed, 336 insertions(+), 284 deletions(-) create mode 100644 solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.ts diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/README.md b/solution/1700-1799/1717.Maximum Score From Removing Substrings/README.md index 0da3ad6ecbc66..523febeecd7df 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/README.md +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/README.md @@ -74,7 +74,25 @@ tags: -### 方法一 +### 方法一:贪心 + +我们不妨假设子字符串 "ab" 的得分总是不低于子字符串 "ba" 的得分,如果不是,我们可以交换 "a" 和 "b",同时交换 $x$ 和 $y$。 + +接下来,我们只需要考虑字符串中只包含 "a" 和 "b" 的情况。如果字符串中包含其他字符,我们可以将其视为一个分割点,将字符串分割成若干个只包含 "a" 和 "b" 的子字符串,然后分别计算每个子字符串的得分。 + +我们观察发现,对于一个只包含 "a" 和 "b" 的子字符串,无论采取什么样的操作,最后一定只剩下一种字符,或者空串。由于每次操作都会同时删除一个 "a" 和一个 "b",因此总的操作次数一定是固定的。我们可以贪心地先删除 "ab",再删除 "ba",这样可以保证得分最大。 + +因此,我们可以使用两个变量 $\textit{cnt1}$ 和 $\textit{cnt2}$ 分别记录 "a" 和 "b" 的数量,然后遍历字符串,根据当前字符的不同情况更新 $\textit{cnt1}$ 和 $\textit{cnt2}$,并计算得分。 + +对于当前遍历到的字符 $c$: + +- 如果 $c$ 是 "a",由于要先删除 "ab",因此此时我们不消除该字符,只增加 $\textit{cnt1}$; +- 如果 $c$ 是 "b",如果此时 $\textit{cnt1} > 0$,我们可以消除一个 "ab",并增加 $x$ 分,否则我们只能增加 $\textit{cnt2}$; +- 如果 $c$ 是其他字符,那么对于该子字符串,我们剩下了一个 $\textit{cnt2}$ 个 "b" 和 $\textit{cnt1}$ 个 "a",我们可以消除 $\min(\textit{cnt1}, \textit{cnt2})$ 个 "ab",并增加 $y$ 分。 + +遍历结束后,我们还需要额外处理一下剩余的 "ab",增加若干个 $y$ 分。 + +时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(1)$。 @@ -83,29 +101,24 @@ tags: ```python class Solution: def maximumGain(self, s: str, x: int, y: int) -> int: + a, b = "a", "b" if x < y: - return self.maximumGain(s[::-1], y, x) - ans = 0 - stk1, stk2 = [], [] + x, y = y, x + a, b = b, a + ans = cnt1 = cnt2 = 0 for c in s: - if c != 'b': - stk1.append(c) - else: - if stk1 and stk1[-1] == 'a': - stk1.pop() + if c == a: + cnt1 += 1 + elif c == b: + if cnt1: ans += x + cnt1 -= 1 else: - stk1.append(c) - while stk1: - c = stk1.pop() - if c != 'b': - stk2.append(c) + cnt2 += 1 else: - if stk2 and stk2[-1] == 'a': - stk2.pop() - ans += y - else: - stk2.append(c) + ans += min(cnt1, cnt2) * y + cnt1 = cnt2 = 0 + ans += min(cnt1, cnt2) * y return ans ``` @@ -114,37 +127,35 @@ class Solution: ```java class Solution { public int maximumGain(String s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - return maximumGain(new StringBuilder(s).reverse().toString(), y, x); + int t = x; + x = y; + y = t; + char c = a; + a = b; + b = c; } - int ans = 0; - Deque stk1 = new ArrayDeque<>(); - Deque stk2 = new ArrayDeque<>(); - for (char c : s.toCharArray()) { - if (c != 'b') { - stk1.push(c); - } else { - if (!stk1.isEmpty() && stk1.peek() == 'a') { - stk1.pop(); + int ans = 0, cnt1 = 0, cnt2 = 0; + int n = s.length(); + for (int i = 0; i < n; ++i) { + char c = s.charAt(i); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1 > 0) { ans += x; + cnt1--; } else { - stk1.push(c); + cnt2++; } - } - } - while (!stk1.isEmpty()) { - char c = stk1.pop(); - if (c != 'b') { - stk2.push(c); } else { - if (!stk2.isEmpty() && stk2.peek() == 'a') { - stk2.pop(); - ans += y; - } else { - stk2.push(c); - } + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += Math.min(cnt1, cnt2) * y; return ans; } } @@ -156,37 +167,30 @@ class Solution { class Solution { public: int maximumGain(string s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - reverse(s.begin(), s.end()); - return maximumGain(s, y, x); + swap(x, y); + swap(a, b); } - int ans = 0; - stack stk1; - stack stk2; + + int ans = 0, cnt1 = 0, cnt2 = 0; for (char c : s) { - if (c != 'b') - stk1.push(c); - else { - if (!stk1.empty() && stk1.top() == 'a') { - stk1.pop(); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1) { ans += x; - } else - stk1.push(c); - } - } - while (!stk1.empty()) { - char c = stk1.top(); - stk1.pop(); - if (c != 'b') - stk2.push(c); - else { - if (!stk2.empty() && stk2.top() == 'a') { - stk2.pop(); - ans += y; - } else - stk2.push(c); + cnt1--; + } else { + cnt2++; + } + } else { + ans += min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += min(cnt1, cnt2) * y; return ans; } }; @@ -195,42 +199,63 @@ public: #### Go ```go -func maximumGain(s string, x int, y int) int { +func maximumGain(s string, x int, y int) (ans int) { + a, b := 'a', 'b' if x < y { - t := []rune(s) - for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { - t[i], t[j] = t[j], t[i] - } - return maximumGain(string(t), y, x) + x, y = y, x + a, b = b, a } - ans := 0 - var stk1 []byte - var stk2 []byte - for i := range s { - if s[i] != 'b' { - stk1 = append(stk1, s[i]) - } else { - if len(stk1) > 0 && stk1[len(stk1)-1] == 'a' { - stk1 = stk1[0 : len(stk1)-1] + + var cnt1, cnt2 int + for _, c := range s { + if c == a { + cnt1++ + } else if c == b { + if cnt1 > 0 { ans += x + cnt1-- } else { - stk1 = append(stk1, s[i]) + cnt2++ } - } - } - for _, c := range stk1 { - if c != 'a' { - stk2 = append(stk2, c) } else { - if len(stk2) > 0 && stk2[len(stk2)-1] == 'b' { - stk2 = stk2[0 : len(stk2)-1] - ans += y - } else { - stk2 = append(stk2, c) - } + ans += min(cnt1, cnt2) * y + cnt1, cnt2 = 0, 0 } } - return ans + ans += min(cnt1, cnt2) * y + return +} +``` + +#### TypeScript + +```ts +function maximumGain(s: string, x: number, y: number): number { + let [a, b] = ['a', 'b']; + if (x < y) { + [x, y] = [y, x]; + [a, b] = [b, a]; + } + + let [ans, cnt1, cnt2] = [0, 0, 0]; + for (let c of s) { + if (c === a) { + cnt1++; + } else if (c === b) { + if (cnt1) { + ans += x; + cnt1--; + } else { + cnt2++; + } + } else { + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; + } + } + ans += Math.min(cnt1, cnt2) * y; + return ans; } ``` diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/README_EN.md b/solution/1700-1799/1717.Maximum Score From Removing Substrings/README_EN.md index 53e3a359595ab..3bd0568e9e45d 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/README_EN.md +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/README_EN.md @@ -74,7 +74,25 @@ Total score = 5 + 4 + 5 + 5 = 19. -### Solution 1 +### Solution 1: Greedy + +Let's assume that the score of the substring "ab" is always not lower than the score of the substring "ba". If not, we can swap "a" and "b", and simultaneously swap $x$ and $y$. + +Next, we only need to consider the case where the string contains only "a" and "b". If the string contains other characters, we can treat them as a dividing point, splitting the string into several substrings that contain only "a" and "b", and then calculate the score for each substring separately. + +We observe that, for a substring containing only "a" and "b", no matter what operations are taken, in the end, there will only be one type of character left, or an empty string. Since each operation will delete one "a" and one "b" simultaneously, the total number of operations is fixed. We can greedily delete "ab" first, then "ba", to ensure the maximum score. + +Therefore, we can use two variables $\textit{cnt1}$ and $\textit{cnt2}$ to record the number of "a" and "b", respectively. Then, we traverse the string, update $\textit{cnt1}$ and $\textit{cnt2}$ based on the current character, and calculate the score. + +For the current character $c$: + +- If $c$ is "a", since we need to delete "ab" first, we do not eliminate this character at this time, only increase $\textit{cnt1}$; +- If $c$ is "b", if $\textit{cnt1} > 0$ at this time, we can eliminate an "ab" and add $x$ points; otherwise, we can only increase $\textit{cnt2}$; +- If $c$ is another character, then for this substring, we are left with $\textit{cnt2}$ "b" and $\textit{cnt1}$ "a", we can eliminate $\min(\textit{cnt1}, \textit{cnt2})$ "ab" and add $y$ points. + +After the traversal is finished, we also need to additionally handle the remaining "ab", adding several $y$ points. + +The time complexity is $O(n)$, where $n$ is the length of the string $s$. The space complexity is $O(1)$. @@ -83,29 +101,24 @@ Total score = 5 + 4 + 5 + 5 = 19. ```python class Solution: def maximumGain(self, s: str, x: int, y: int) -> int: + a, b = "a", "b" if x < y: - return self.maximumGain(s[::-1], y, x) - ans = 0 - stk1, stk2 = [], [] + x, y = y, x + a, b = b, a + ans = cnt1 = cnt2 = 0 for c in s: - if c != 'b': - stk1.append(c) - else: - if stk1 and stk1[-1] == 'a': - stk1.pop() + if c == a: + cnt1 += 1 + elif c == b: + if cnt1: ans += x + cnt1 -= 1 else: - stk1.append(c) - while stk1: - c = stk1.pop() - if c != 'b': - stk2.append(c) + cnt2 += 1 else: - if stk2 and stk2[-1] == 'a': - stk2.pop() - ans += y - else: - stk2.append(c) + ans += min(cnt1, cnt2) * y + cnt1 = cnt2 = 0 + ans += min(cnt1, cnt2) * y return ans ``` @@ -114,37 +127,35 @@ class Solution: ```java class Solution { public int maximumGain(String s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - return maximumGain(new StringBuilder(s).reverse().toString(), y, x); + int t = x; + x = y; + y = t; + char c = a; + a = b; + b = c; } - int ans = 0; - Deque stk1 = new ArrayDeque<>(); - Deque stk2 = new ArrayDeque<>(); - for (char c : s.toCharArray()) { - if (c != 'b') { - stk1.push(c); - } else { - if (!stk1.isEmpty() && stk1.peek() == 'a') { - stk1.pop(); + int ans = 0, cnt1 = 0, cnt2 = 0; + int n = s.length(); + for (int i = 0; i < n; ++i) { + char c = s.charAt(i); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1 > 0) { ans += x; + cnt1--; } else { - stk1.push(c); + cnt2++; } - } - } - while (!stk1.isEmpty()) { - char c = stk1.pop(); - if (c != 'b') { - stk2.push(c); } else { - if (!stk2.isEmpty() && stk2.peek() == 'a') { - stk2.pop(); - ans += y; - } else { - stk2.push(c); - } + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += Math.min(cnt1, cnt2) * y; return ans; } } @@ -156,37 +167,30 @@ class Solution { class Solution { public: int maximumGain(string s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - reverse(s.begin(), s.end()); - return maximumGain(s, y, x); + swap(x, y); + swap(a, b); } - int ans = 0; - stack stk1; - stack stk2; + + int ans = 0, cnt1 = 0, cnt2 = 0; for (char c : s) { - if (c != 'b') - stk1.push(c); - else { - if (!stk1.empty() && stk1.top() == 'a') { - stk1.pop(); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1) { ans += x; - } else - stk1.push(c); - } - } - while (!stk1.empty()) { - char c = stk1.top(); - stk1.pop(); - if (c != 'b') - stk2.push(c); - else { - if (!stk2.empty() && stk2.top() == 'a') { - stk2.pop(); - ans += y; - } else - stk2.push(c); + cnt1--; + } else { + cnt2++; + } + } else { + ans += min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += min(cnt1, cnt2) * y; return ans; } }; @@ -195,42 +199,63 @@ public: #### Go ```go -func maximumGain(s string, x int, y int) int { +func maximumGain(s string, x int, y int) (ans int) { + a, b := 'a', 'b' if x < y { - t := []rune(s) - for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { - t[i], t[j] = t[j], t[i] - } - return maximumGain(string(t), y, x) + x, y = y, x + a, b = b, a } - ans := 0 - var stk1 []byte - var stk2 []byte - for i := range s { - if s[i] != 'b' { - stk1 = append(stk1, s[i]) - } else { - if len(stk1) > 0 && stk1[len(stk1)-1] == 'a' { - stk1 = stk1[0 : len(stk1)-1] + + var cnt1, cnt2 int + for _, c := range s { + if c == a { + cnt1++ + } else if c == b { + if cnt1 > 0 { ans += x + cnt1-- } else { - stk1 = append(stk1, s[i]) + cnt2++ } - } - } - for _, c := range stk1 { - if c != 'a' { - stk2 = append(stk2, c) } else { - if len(stk2) > 0 && stk2[len(stk2)-1] == 'b' { - stk2 = stk2[0 : len(stk2)-1] - ans += y - } else { - stk2 = append(stk2, c) - } + ans += min(cnt1, cnt2) * y + cnt1, cnt2 = 0, 0 } } - return ans + ans += min(cnt1, cnt2) * y + return +} +``` + +#### TypeScript + +```ts +function maximumGain(s: string, x: number, y: number): number { + let [a, b] = ['a', 'b']; + if (x < y) { + [x, y] = [y, x]; + [a, b] = [b, a]; + } + + let [ans, cnt1, cnt2] = [0, 0, 0]; + for (let c of s) { + if (c === a) { + cnt1++; + } else if (c === b) { + if (cnt1) { + ans += x; + cnt1--; + } else { + cnt2++; + } + } else { + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; + } + } + ans += Math.min(cnt1, cnt2) * y; + return ans; } ``` diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.cpp b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.cpp index 06b0a72a47abc..32b13e472e850 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.cpp +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.cpp @@ -1,37 +1,30 @@ class Solution { public: int maximumGain(string s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - reverse(s.begin(), s.end()); - return maximumGain(s, y, x); + swap(x, y); + swap(a, b); } - int ans = 0; - stack stk1; - stack stk2; + + int ans = 0, cnt1 = 0, cnt2 = 0; for (char c : s) { - if (c != 'b') - stk1.push(c); - else { - if (!stk1.empty() && stk1.top() == 'a') { - stk1.pop(); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1) { ans += x; - } else - stk1.push(c); - } - } - while (!stk1.empty()) { - char c = stk1.top(); - stk1.pop(); - if (c != 'b') - stk2.push(c); - else { - if (!stk2.empty() && stk2.top() == 'a') { - stk2.pop(); - ans += y; - } else - stk2.push(c); + cnt1--; + } else { + cnt2++; + } + } else { + ans += min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += min(cnt1, cnt2) * y; return ans; } }; \ No newline at end of file diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.go b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.go index b9748e1bdf53c..6afa9dfe39e26 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.go +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.go @@ -1,37 +1,26 @@ -func maximumGain(s string, x int, y int) int { +func maximumGain(s string, x int, y int) (ans int) { + a, b := 'a', 'b' if x < y { - t := []rune(s) - for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 { - t[i], t[j] = t[j], t[i] - } - return maximumGain(string(t), y, x) + x, y = y, x + a, b = b, a } - ans := 0 - var stk1 []byte - var stk2 []byte - for i := range s { - if s[i] != 'b' { - stk1 = append(stk1, s[i]) - } else { - if len(stk1) > 0 && stk1[len(stk1)-1] == 'a' { - stk1 = stk1[0 : len(stk1)-1] + + var cnt1, cnt2 int + for _, c := range s { + if c == a { + cnt1++ + } else if c == b { + if cnt1 > 0 { ans += x + cnt1-- } else { - stk1 = append(stk1, s[i]) + cnt2++ } - } - } - for _, c := range stk1 { - if c != 'a' { - stk2 = append(stk2, c) } else { - if len(stk2) > 0 && stk2[len(stk2)-1] == 'b' { - stk2 = stk2[0 : len(stk2)-1] - ans += y - } else { - stk2 = append(stk2, c) - } + ans += min(cnt1, cnt2) * y + cnt1, cnt2 = 0, 0 } } - return ans + ans += min(cnt1, cnt2) * y + return } \ No newline at end of file diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.java b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.java index f80ea3b25299e..3579b26af2f8c 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.java +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.java @@ -1,36 +1,34 @@ class Solution { public int maximumGain(String s, int x, int y) { + char a = 'a', b = 'b'; if (x < y) { - return maximumGain(new StringBuilder(s).reverse().toString(), y, x); + int t = x; + x = y; + y = t; + char c = a; + a = b; + b = c; } - int ans = 0; - Deque stk1 = new ArrayDeque<>(); - Deque stk2 = new ArrayDeque<>(); - for (char c : s.toCharArray()) { - if (c != 'b') { - stk1.push(c); - } else { - if (!stk1.isEmpty() && stk1.peek() == 'a') { - stk1.pop(); + int ans = 0, cnt1 = 0, cnt2 = 0; + int n = s.length(); + for (int i = 0; i < n; ++i) { + char c = s.charAt(i); + if (c == a) { + cnt1++; + } else if (c == b) { + if (cnt1 > 0) { ans += x; + cnt1--; } else { - stk1.push(c); + cnt2++; } - } - } - while (!stk1.isEmpty()) { - char c = stk1.pop(); - if (c != 'b') { - stk2.push(c); } else { - if (!stk2.isEmpty() && stk2.peek() == 'a') { - stk2.pop(); - ans += y; - } else { - stk2.push(c); - } + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; } } + ans += Math.min(cnt1, cnt2) * y; return ans; } } \ No newline at end of file diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.py b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.py index 505a9e910271c..e68d660bb8e15 100644 --- a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.py +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.py @@ -1,26 +1,21 @@ class Solution: def maximumGain(self, s: str, x: int, y: int) -> int: + a, b = "a", "b" if x < y: - return self.maximumGain(s[::-1], y, x) - ans = 0 - stk1, stk2 = [], [] + x, y = y, x + a, b = b, a + ans = cnt1 = cnt2 = 0 for c in s: - if c != 'b': - stk1.append(c) - else: - if stk1 and stk1[-1] == 'a': - stk1.pop() + if c == a: + cnt1 += 1 + elif c == b: + if cnt1: ans += x + cnt1 -= 1 else: - stk1.append(c) - while stk1: - c = stk1.pop() - if c != 'b': - stk2.append(c) + cnt2 += 1 else: - if stk2 and stk2[-1] == 'a': - stk2.pop() - ans += y - else: - stk2.append(c) + ans += min(cnt1, cnt2) * y + cnt1 = cnt2 = 0 + ans += min(cnt1, cnt2) * y return ans diff --git a/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.ts b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.ts new file mode 100644 index 0000000000000..95cd21ad7a48d --- /dev/null +++ b/solution/1700-1799/1717.Maximum Score From Removing Substrings/Solution.ts @@ -0,0 +1,27 @@ +function maximumGain(s: string, x: number, y: number): number { + let [a, b] = ['a', 'b']; + if (x < y) { + [x, y] = [y, x]; + [a, b] = [b, a]; + } + + let [ans, cnt1, cnt2] = [0, 0, 0]; + for (let c of s) { + if (c === a) { + cnt1++; + } else if (c === b) { + if (cnt1) { + ans += x; + cnt1--; + } else { + cnt2++; + } + } else { + ans += Math.min(cnt1, cnt2) * y; + cnt1 = 0; + cnt2 = 0; + } + } + ans += Math.min(cnt1, cnt2) * y; + return ans; +}