题目
给你一个字符串 s 和两个整数 x 和 y 。你可以执行下面两种操作任意次。
- 删除子字符串
"ab"并得到x分。- 比方说,从
"cabxbae"删除ab,得到"cxbae"。
- 比方说,从
- 删除子字符串
"ba"并得到y分。- 比方说,从
"cabxbae"删除ba,得到"cabxe"。
- 比方说,从
请返回对 s 字符串执行上面操作若干次能得到的最大得分。
跳转链接:LeetCode1717
解析
假设 x > y,所以在删除的过程中会出现以下情况:
1.当出现 "aabb" 时,我们可以删除两个 “ab”,得分为 2x。
2.当出现 “bbaa” 时,我们可以删除两个 “ba”,得分为 2y。
3.当出现 “abab” 时,我们可以删除两个 “ab”,得分为 2x;或者删除一个 “ba” 和一个 “ab”,得分为 x + y。由于 x > y,所以我们优先删除两个 “ab”,这样得分最大。
4.当出现 “baba” 时,我们可以删除两个 “ba”,得分为 2y;或者删除一个 “ba”和一个 “ab”,得分为x+y。由于 x > y,所以我们优先删除一个 “ba” 和一个 “ab”,这样得分最大。
5.当出现 “caba” 等包含非 “a” 或 “b” 的字母时,我们会发现优先删除 “ab” 得分会更高。
综上,无论在什么情况下优先删除“ab”(当x > y时)总会得到更高的分数,因此我们可以考虑贪心来解题。
继续假设 x > y,因此我们优先删除“ab”。遍历字符串:
情况1:当出现“a”时,我们用 count1 进行计数,表示当前可用于组合 “ab” 的 “a” 的个数;
情况2:当出现 “b” 时,如果有可用的 “a” 则得 x 分,同时 count1 减一;
情况3:当出现 “b” 时,如果没有可用的 “a”则 count2 加一,表示可用于组合 “ba” 的 “b” 的个数;
情况4:当出现其他字母时,我们可以将其看作一个分割线,因为出现其他字母时,前字符串与后字符串被分割成俩部分,两者之间不会出现 “ab” 或者 “ba” 的组合,所以这时我们可以将前面的字符串进行结算。由于前面的字符串中 “ab” 的情况在情况2中我们已考虑完,所以我们可以只考虑 “ba” 的情况。使用 ans += y * Math.min(count1, count2); 来计算得分,并将计数器归零。
public class Solution {
public static int maximumGain(String s, int x, int y) {
char a = 'a', b = 'b';
//如果x < y,那么需要优先删除“ba”,这时我们只需要将x和y,a和b的值互换即可
if(x < y){
int t = x;
x = y;
y = t;
a = 'b';
b = 'a';
}
//count1用于记录当前可用的变量a的个数
//count2用于记录当前可用的变量b的个数
int count1 = 0, count2 = 0, n = s.length(), ans = 0;
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
//当当前的字母与变量a相等时,直接计数,因为我们要优先删除得分大的组合
if(ch == a){
count1++;
}
else if(ch == b){
//如果变量ch前面存在可用的变量a,则删除
if(count1 > 0){
count1--;
ans += x;
}
//如果变量ch前面不存在可用的变量a,则count2累加
else{
count2++;
}
}
/*
当出现“a”或“b”之外的字母时,前面已经不存在得分高的组合了,
同时由于有其他字母分割,变量ch前面的字母与后面的字母不可能
再组合了,所以此时应该将变量ch前的得分低的组合的得分计算出
来并将两个计数器归零
* */
else{
ans += y * Math.min(count1, count2);
count1 = 0;
count2 = 0;
}
}
//遍历完字符串后还需要计算一次得分低的组合的得分
ans += y * Math.min(count1, count2);
return ans;
}
}
872

被折叠的 条评论
为什么被折叠?



