LeetCode 题解 —— 5551. 使字符串平衡的最少删除次数

题目相关

题目链接

LeetCode 中国,https://leetcode-cn.com/contest/biweekly-contest-39/problems/minimum-deletions-to-make-string-balanced/。

Problem Statement

给你一个字符串 s ,它仅包含字符 'a' 和 'b'​​​​ 。

你可以删除 s 中任意数目的字符,使得 s 平衡 。我们称 s 平衡的 当不存在下标对 (i,j) 满足 i < j 且 s[i] = 'b' 同时 s[j]= 'a' 。

请你返回使 s 平衡 的 最少 删除次数。

Samples 1

输入:s = "aababbab"
输出:2
解释:你可以选择以下任意一种方案:
下标从 0 开始,删除第 2 和第 6 个字符("aababbab" -> "aaabbb"),
下标从 0 开始,删除第 3 和第 6 个字符("aababbab" -> "aabbbb")。

Samples 2

输入:s = "bbaaaaabb"
输出:2
解释:唯一的最优解是删除最前面两个字符。

Constraints

  • 1 <= s.length <= 105
  • s[i] 要么是 'a' 要么是 'b' 。​

题解报告

样例数据分析

题目分析

LeetCode 官方将本题难度定为中等。通过阅读题目,字符串就会出现 a 和 b 两种字符。我们发现字符 b 是关键,因为后面的字符可能导致新字符串变成不平衡。因此,出现字符 b 后,需要特别操作。一般来说,这个操作就是记录 b 的个数。下面我们来分析一下样例数据。

样例 1

1、下标为零的字符 s[0]='a'。对应的字符串为 "aa",符合平衡字符串,所以不需要处理;

2、下标为一的字符 s[1]='a'。对应的字符串为 "aa",符合平衡字符串,所以不需要处理;

3、下标为二的字符 s[2]='b'。对应的字符串为 "aab",符合平衡字符串,所以不需要处理。但是如果下一个字符为 a,那么就不是平衡字符串了,这样我们只要删除一个 b 就可以变成平衡字符串。因此将 b 计数,cnt=1;

4、下标为三的字符 s[3]='a'。对应的字符串为 "aaba",不符合平衡字符串,我们删除 s[2],将字符串变成 "aaa";或者删除 s[3],将字符串变成 “aab”。考虑到后面还有字符,因此将字符串变成 “aaa” 更符合要求,这样我们 cnt 减一变成 0;这样我们的操作为 1;

5、下标为四的字符 s[4]='b'。对应的字符串为 "aaab",符合平衡字符串。同样将 b 计数,cnt=1;

6、下标为五的字符 s[5]='b'。对应的字符串为 "aaabb",符合平衡字符串。同样将 b 计数,cnt=2;

7、下标为六的字符 s[6]='a'。对应的字符串为 "aaabba",不符合平衡字符串。我们只需要删除最后的 a 就可以变成平衡字符串 “aaabb”,因此 cnt 减一变成 1;这样我们的操作为 2;

8、下标为七的字符 s[7]='b'。对应的字符串为 "aaabbb",符合平衡字符串。同样将 b 计数,cnt=2;

这样,我们得到平衡字符串 “aaabbb”,操作的次数为 2。

这里,我们观察到,当字符为 a 的时候,要考虑字符 b 的计数情况。如果计数为零,说明到目前位置,没有出现过字符 b,自然字符串是平衡的,不需要任何操作。如果计数不为零,说明出现了字符 b,字符串不是平衡的,我们可以删除一个字符,让字符串变成平衡,这样我们将 cnt 减一,操作数 ans 加一。

样例 2

1、下标为零的字符 s[0]='b'。对应的字符串为 "b",符合平衡字符串,所以不需要处理,但是我们记录 cnt=1;

2、下标为一的字符 s[1]='b'。对应的字符串为 "bb",符合平衡字符串,所以不需要处理,但是我们记录 cnt=2;

3、下标为二的字符 s[2]='a'。对应的字符串为 "bba",不符合平衡字符串。要变成平衡字符串,只需要删除最后的字符即可,这样平衡字符串为 "bb"。这样我们 ans=1,cnt=1。

4、下标为三的字符 s[3]='a'。对应的字符串为 "bba",不符合平衡字符串。要变成平衡字符串,只需要删除最后的字符即可,这样平衡字符串为 "aa"(由于 cnt=0,b 和 a 就是等价的)。这样我们 ans=2,cnt=0。

5、下标为四的字符 s[4]='a'。对应的字符串为 "aaa",符合平衡字符串,所以不需要处理;

6、下标为五的字符 s[5]='a'。对应的字符串为 "aaaa",符合平衡字符串,所以不需要处理;

7、下标为六的字符 s[6]='a'。对应的字符串为 "aaaaa",符合平衡字符串,所以不需要处理;

8、下标为七的字符 s[7]='b'。对应的字符串为 "aaaaab",符合平衡字符串,所以不需要处理;

9、下标为八的字符 s[8]='b'。对应的字符串为 "aaaaabb",符合平衡字符串,所以不需要处理。

贪心思路

从上面的数据分析,我们可以看出,使用贪心是可以的。伪码为:

i 从 0 到结束遍历字符串的每一个字符
    如果字符为 b,cnt加一。
    如果字符为 a,如果 cnt 大于 0,说明不平衡,ans加一,cnt减一

AC 参考代码

class Solution {
public:
    int minimumDeletions(string s) {
        int cnt=0;//字母b
        int ans=0;
        for (int i=0; i0) {
                    ans++;
                    cnt--;
                }
            }
        }
        return ans;
    }
};

LeetCode 题解 —— 5551. 使字符串平衡的最少删除次数_第1张图片

时间复杂度

O(N)

空间复杂度

O(1)

动态规划

本题通过删除字符达到字符串平衡,因此可以考虑使用动态规划的思路。我们知道动态规划主要是有以下几个部分组成:

1、动态规划数组定义;

2、初始值;

3、边界条件;

4、搜索方法

5、状态转移方程。

7、返回值

DP 数组定义

由于本题可以删除字符 a,也可以删除字符 b。因此我们考虑使用两个数组来表示。即 dpa 和 dpb。

dpa 表示字符串以 a 结尾且字符串是平衡最少删除次数。dpa[i] 表示到第 i 位结束最少操作次数。

dpb 表示字符串以 b 结尾且字符串是平衡最少删除次数。dpp[i] 表示到第 i 位结束最少操作次数。

初始值

开始的时候,字符串肯定是平衡的。因此 dpa[0]=0,dpb[0]=0。

边界条件

没有。

搜索方法

自然是从 0 开始向 n 搜索。

状态转移方程

根据 s[i] 的数据,我们可以得出状态转移方程:

如果 s[i]='a',我们将在原来已经平衡的字符串后面加上一个字符 a。对于 dpa 而言,加上 a 后,字符串还是平衡的,因此 dpa[i+1]=dpa[i];对于 dpb 而言,加上 a 后,字符串肯定是不平衡的,我们需要删除这个字符 a,才可以达到字符串是平衡而且以 b 位结尾,因此 dpb[i+1]=dpb[i]+1,就是多操作一次。

如果 s[i]='b',我们将在原来已经平衡的字符串后面加上一个字符 b。对于 dpa 而言,加上 b 后,字符串肯定是不平衡的,我们需要删除这个字符 b,才可以达到字符串是平衡而且以 a 位结尾,因此 dpa[i+1]=dpa[i]+1;对于 dpb 而言,加上 b 后,字符串还是平衡的,因此 dpb[i+1]=dpb[i]。

返回值

自然是 dpa[len] 和 dpb[len] 最小值。

AC 参考代码

class Solution {
public:
    int minimumDeletions(string s) {
        int len=s.length();
        if (0==len) {
            return 0;
        }

        vector dpa(len+1, 0);//以a结尾
        vector dpb(len+1, 0);//以b结尾

        for (int i=2; i

LeetCode 题解 —— 5551. 使字符串平衡的最少删除次数_第2张图片

时间复杂度

O(N)

空间复杂度

O(N)

你可能感兴趣的:(OJ题解,#,LeetCode题解,LeetCode,LeetCode题解,5551)