【数据结构-邻项消除】力扣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就是最大得分。

相关推荐
劲夫学编程1 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪1 小时前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
师太,答应老衲吧5 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown6 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错7 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny8 小时前
计算网络信号
java·算法·华为