【数据结构-邻项消除】力扣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 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱敲代码的憨仔1 小时前
《线性代数的本质》
线性代数·算法·决策树
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins1 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
阿史大杯茶1 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
Chris _data2 小时前
二叉树oj题解析
java·数据结构
დ旧言~2 小时前
【高阶数据结构】图论
算法·深度优先·广度优先·宽度优先·推荐算法
张彦峰ZYF2 小时前
投资策略规划最优决策分析
分布式·算法·金融
The_Ticker2 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Lenyiin3 小时前
02.06、回文链表
数据结构·leetcode·链表