【数据结构-邻项消除】力扣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

模拟栈

cpp 复制代码
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就是最大得分。

贪心

cpp 复制代码
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就是最大得分。

相关推荐
sp4222 分钟前
白话 LRU 缓存及链表的数据结构讲解(二)
算法
PineappleCoder1 小时前
为什么说发布 - 订阅是代码的 “万能胶水”?解耦逻辑全解析
前端·javascript·算法
墨染点香1 小时前
LeetCode 刷题【43. 字符串相乘】
算法·leetcode·职场和发展
weixin_307779131 小时前
VS Code配置MinGW64编译Ipopt库
开发语言·c++·vscode·算法
Keying,,,,1 小时前
力扣hot100 | 矩阵 | 73. 矩阵置零、54. 螺旋矩阵、48. 旋转图像、240. 搜索二维矩阵 II
python·算法·leetcode·矩阵
sp422 小时前
白话 LRU 缓存及链表的数据结构讲解(一)
算法
_不会dp不改名_3 小时前
leetcode_42 接雨水
算法·leetcode·职场和发展
Swaggy T3 小时前
自动驾驶轨迹规划算法——Apollo EM Planner
人工智能·算法·自动驾驶
野生的编程萌新3 小时前
从冒泡到快速排序:探索经典排序算法的奥秘(二)
c语言·开发语言·数据结构·c++·算法·排序算法
iLoyalty3 小时前
防御保护15
算法·哈希算法