Medium
题目描述
给你一个字符串 s 和两个整数 x 和 y。你可以执行下面两种操作任意次。
- 删除子字符串
"ab"并得到x分。- 例如,从
"cabxbae"删除ab,得到"cxbae"。
- 例如,从
- 删除子字符串
"ba"并得到y分。- 例如,从
"cabxbae"删除ba,得到"cabxe"。
- 例如,从
请返回在字符串 s 上执行上述操作若干次能够获得的最大分数。
示例 1:
输入:s = "cdbcbbaaabab", x = 4, y = 5
输出:19
解释:
- 删除 "cdbcbbaaabab" 中加下划线的 "ba"。现在 s = "cdbcbbaaab",分数增加 5 分。
- 删除 "cdbcbbaaab" 中加下划线的 "ab"。现在 s = "cdbcbbaa",分数增加 4 分。
- 删除 "cdbcbbaa" 中加下划线的 "ba"。现在 s = "cdbcba",分数增加 5 分。
- 删除 "cdbcba" 中加下划线的 "ba"。现在 s = "cdbc",分数增加 5 分。
总分数 = 5 + 4 + 5 + 5 = 19。
示例 2:
输入:s = "aabbaaxybbaabb", x = 5, y = 4
输出:20
约束条件:
1 <= s.length <= 10^51 <= x, y <= 10^4s只包含小写英文字母。
解题思路
这是一个贪心策略问题。核心思路是优先移除得分更高的子字符串。
分析:
- 我们有两种操作:“ab” 得 x 分,“ba” 得 y 分
- 关键洞察:应该优先处理得分更高的子字符串,因为先处理高分的不会影响低分的机会
- 如果 x > y,优先移除 “ab”;否则优先移除 “ba”
算法步骤:
- 比较 x 和 y 的大小,确定优先处理的子字符串
- 使用栈(或字符串)进行第一轮处理:
- 遍历字符串,如果当前字符与栈顶字符能组成高优先级子字符串,则移除并加分
- 否则将当前字符入栈
- 对第一轮处理后的结果,再进行第二轮处理,移除剩余的另一种子字符串
时间复杂度: O(n),每个字符最多被处理两次 空间复杂度: O(n),栈的空间
这种方法保证了得到最大分数,因为贪心策略确保我们不会错过任何可能的高分组合。
代码实现
class Solution {
public:
int maximumGain(string s, int x, int y) {
// 确保 x >= y,如果不是则交换
if (x < y) {
swap(x, y);
// 同时交换对应的字符
for (char& c : s) {
if (c == 'a') c = 'b';
else if (c == 'b') c = 'a';
}
}
int score = 0;
// 第一轮:移除 "ab"(高分)
string stack;
for (char c : s) {
if (!stack.empty() && stack.back() == 'a' && c == 'b') {
stack.pop_back();
score += x;
} else {
stack.push_back(c);
}
}
// 第二轮:移除 "ba"(低分)
string result;
for (char c : stack) {
if (!result.empty() && result.back() == 'b' && c == 'a') {
result.pop_back();
score += y;
} else {
result.push_back(c);
}
}
return score;
}
};
class Solution:
def maximumGain(self, s: str, x: int, y: int) -> int:
# 确保优先处理高分的子字符串
if x < y:
x, y = y, x
s = s.replace('a', 'c').replace('b', 'a').replace('c', 'b')
score = 0
# 第一轮:移除 "ab"(高分)
stack = []
for c in s:
if stack and stack[-1] == 'a' and c == 'b':
stack.pop()
score += x
else:
stack.append(c)
# 第二轮:移除 "ba"(低分)
result = []
for c in stack:
if result and result[-1] == 'b' and c == 'a':
result.pop()
score += y
else:
result.append(c)
return score
public class Solution {
public int MaximumGain(string s, int x, int y) {
// 确保 x >= y
if (x < y) {
(x, y) = (y, x);
s = s.Replace('a', 'c').Replace('b', 'a').Replace('c', 'b');
}
int score = 0;
// 第一轮:移除 "ab"(高分)
var stack = new List<char>();
foreach (char c in s) {
if (stack.Count > 0 && stack[stack.Count - 1] == 'a' && c == 'b') {
stack.RemoveAt(stack.Count - 1);
score += x;
} else {
stack.Add(c);
}
}
// 第二轮:移除 "ba"(低分)
var result = new List<char>();
foreach (char c in stack) {
if (result.Count > 0 && result[result.Count - 1] == 'b' && c == 'a') {
result.RemoveAt(result.Count - 1);
score += y;
} else {
result.Add(c);
}
}
return score;
}
}
var maximumGain = function(s, x, y) {
// 确保优先处理高分的子字符串
if (x < y) {
[x, y] = [y, x];
s = s.replace(/a/g, 'c').replace(/b/g, 'a').replace(/c/g, 'b');
}
let score = 0;
// 第一轮:移除 "ab"(高分)
let stack = [];
for (let c of s) {
if (stack.length > 0 && stack[stack.length - 1]
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 每个字符最多被处理两次,n为字符串长度 |
| 空间复杂度 | O(n) | 栈空间最坏情况下存储所有字符 |