【数据结构-邻项消除】力扣1717. 删除子字符串的最大得分
给你一个字符串 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
模拟栈
class Solution {
public:int maximumGain(string s, int x, int y) {int a1, a2;string b1, b2;if(x > y){a1 = x;a2 = y;b1 = "ab";b2 = "ba";} else {a1 = y;a2 = x;b1 = "ba";b2 = "ab";}int ans = 0;string st1 = "";// 优先删除高分组合for(char c : s){st1.push_back(c);if(st1.size() >= 2 && st1.substr(st1.size() - 2, 2) == b1){st1.erase(st1.end() - 2, st1.end());ans += a1;}}string st2 = "";// 删除低分组合for(char c : st1){st2.push_back(c);if(st2.size() >= 2 && st2.substr(st2.size() - 2, 2) == b2){st2.erase(st2.end() - 2, st2.end());ans += a2;}}return ans;}
};
这是我一开始采用的方式,核心思路是我们要优先删除分数更大的字符串,然后再去删除分数较小的字符串。我们首先定义一个栈st1,不断往里面推入字符串s的字符,每当推入字符后,栈从上往下第一个元素和第二个元素如果连起来等于分数较大的字符串,那么我们就将它删除,并加上最大得分。然后再定义一个栈st2,遍历处理过一遍的字符串st1,遍历里面的字符,逐一删除掉较小的分的字符串,并加上相应的得分。最后ans就是最大得分。
贪心
class Solution {
public:int maximumGain(string s, int x, int y) {int n = s.size();if(x < y){swap(x, y);for(int i = 0; i < n; i++){if(s[i] == 'a') s[i] = 'b';else if(s[i] == 'b') s[i] = 'a';}}int ret = 0;int i = 0;while(i < n){while(i < n && s[i] != 'a' && s[i] != 'b') i++;int ca = 0, cb = 0;while(i < n && (s[i] == 'a' || s[i] == 'b')){if(s[i] == 'a'){ca++;}else{if(ca > 0){ca--;ret += x; }else{cb++;}}i++;}ret += min(ca, cb) * y;}return ret;}
};
该方法的时间复杂度和空间复杂度都会更优。
首先核心思路不变,先删除得分较大的字符串。在这里只有两个字符串"ab"和"ba",不妨假设 “ab” 的得分总是不低于 “ba”;否则,我们将字符串中的字符 a 换成 b,b 换成 a,再交换 x 和 y 即可。
接下来是主体部分:
第一个while的目的是让指针遍历完数组。
第二个while的目的是跳过除了a或者b以外的其他字符。
第三个while的目的是记录在一个只有a和b字符的部分,a的数量和b的数量是多少。该while是贪心的思想的核心,我们因为已经假设ab的得分较大,那么当遍历字符是a的时候,我们直接记录a的数量,当字符是b的时候,并且在该部分字符串中,依旧存在a,那么他们就最终能构成字符串"ab"。如果不存在a,那么就记录b的数量。我们记录完删除"ab"得到的得分后,还要记录删除"ba"得到的得分,这取决于在删除完"ab"操作后,剩余的a和b的数量的较小值乘以y。
最后ret就是最大得分。