【每日一题Day138】LC1653使字符串平衡的最少删除次数 | 前后缀 动态规划

简介: 【每日一题Day138】LC1653使字符串平衡的最少删除次数 | 前后缀 动态规划

使字符串平衡的最少删除次数【LC1653】

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

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

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

这两天感觉脑子有点秀逗

前后缀分解

  • 思路:
  • 如果字符串是平衡的,那么所有的a都在所有b的左边,此时有两种特殊情况字符串全为a或者全部b
  • 那么我们可以枚举所有的分割线,将s分为前缀和后缀,并保证前缀都是a后缀都是b,那么我们需要统计前缀中b的个数和后缀中a的个数,删除的次数即为两者之和,记录最小值返回既可


  • 既可
  • 实现
    先统计整个后缀字符串中所有的a的个数,即为整个字符串都为b时需要的删除次数d e l ,然后右移分割线,如果当前字符是a,那么删除次数减小1,如果当前字符是b,那么删除字符增加1
class Solution {
    public int minimumDeletions(String s) {
        // a全部在b的左边       
        int del = 0;
        for (char c : s.toCharArray()){
            if (c == 'a'){
                del++;
            }
        }
        int res = del;
        for (char c : s.toCharArray()){
            if (c == 'a'){
                del--;
                res = Math.min(del, res);
            }else{
                del++;
            }
            // 'a' -> -1    'b' -> 1
            // del += (c - 'a') * 2 - 1;            
        }
    return res;
    }
}

复杂度

  • 时间复杂度:O ( n )
  • 空间复杂度:O ( 1 )

动态规划

  • 思路:考虑s的某个字母对结果的影响
  • 如果s[i]是b,那么不需要删除,s[0,i]为平衡字符串所需要的次数即为s[0,i-1]为平衡字符串的次数
  • 字符串的次数
  • 如果s[i]是a,那么即可以保留它也可以删除它
  • 保留它,那么需要删除s[0,i-1]中所有的b
  • 删除它,s[0,i]为平衡字符串所需要的次数即为「s[0,i-1]为平衡字符串的次数」+1
  • 因此可以使用动态规划实现
  • 动态规划
  1. 确定dp数组(dp table)以及下标的含义
    dp[i]为使s的前i个字母平衡的最少删除次数


2.确定递推公式

  • 如果s[i]是b

image.png


3.dp数组如何初始化

dp[0] = 0;

4.确定遍历顺序
从前往后遍历nums

5.举例推导dp数组

class Solution {
    public int minimumDeletions(String s) {
        int n = s.length();
        int[] dp = new int[n + 1];
        dp[0] = 0;
        int cntB = 0;
        for (int i = 0; i < n; i++){
            if (s.charAt(i) == 'b'){
                dp[i + 1] = dp[i];
                cntB++;
            }else{
                dp[i + 1] = Math.min(dp[i] + 1, cntB);
            }
        }       
        return dp[n];
    }
}

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

优化空间复杂度

class Solution {
    public int minimumDeletions(String s) {
        int n = s.length();
        int dp = 0;
        int cntB = 0;
        for (int i = 0; i < n; i++){
            if (s.charAt(i) == 'b'){
                cntB++;
            }else{
                dp = Math.min(dp + 1, cntB);
            }
        }
        return dp;
    }
}

复杂度

时间复杂度:O ( n )

空间复杂度:O ( 1 )

目录
相关文章
|
6月前
【每日一题Day191】LC2423删除字符使频率相同 | 枚举 分类讨论
【每日一题Day191】LC2423删除字符使频率相同 | 枚举 分类讨论
46 0
|
6月前
【每日一题Day118】LC1124表现良好的最长时间段 | 前缀和+单调栈/哈希表
【每日一题Day118】LC1124表现良好的最长时间段 | 前缀和+单调栈/哈希表
52 0
|
6月前
【每日一题Day117】LC1234替换子串得到平衡字符串 | 双指针
【每日一题Day117】LC1234替换子串得到平衡字符串 | 双指针
44 0
|
6月前
【每日一题Day278】LC2500删除每行中的最大值 | 排序+模拟
【每日一题Day278】LC2500删除每行中的最大值 | 排序+模拟
47 0
|
6月前
【每日一题Day151】LC1625执行操作后字典序最小的字符串 | BFS
【每日一题Day151】LC1625执行操作后字典序最小的字符串 | BFS
37 0
|
6月前
|
测试技术 索引
【每日一题Day296】LC833字符串中的查找与替换 | 排序+模拟
【每日一题Day296】LC833字符串中的查找与替换 | 排序+模拟
44 0
|
6月前
【每日一题Day233】LC1170比较字符串最小字母出现频次 | 前缀和
【每日一题Day233】LC1170比较字符串最小字母出现频次 | 前缀和
38 0
|
6月前
【每日一题Day308】LC57插入区间 | 模拟
【每日一题Day308】LC57插入区间 | 模拟
46 0
|
6月前
【每日一题Day152】LC1012至少有1位重复的数字 | 数位dp
【每日一题Day152】LC1012至少有1位重复的数字 | 数位dp
48 0
|
数据建模
【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟
思路:双指针遍历两个字符串,贪心比较字符的字典顺序,并添加至结果集
75 0
【每日一题Day66】LC1754构造字典序最大的合并字符串 | 贪心 双指针模拟