【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法一)前后缀分解

Problem: 1653. 使字符串平衡的最少删除次数

文章目录

  • [1. 整体思路](#1. 整体思路)
  • [2. 完整代码](#2. 完整代码)
  • [3. 时空复杂度](#3. 时空复杂度)
      • [时间复杂度: O ( N ) O(N) O(N)](#时间复杂度: O ( N ) O(N) O(N))
      • [空间复杂度: O ( N ) O(N) O(N) 或 O ( 1 ) O(1) O(1)](#空间复杂度: O ( N ) O(N) O(N) 或 O ( 1 ) O(1) O(1))

1. 整体思路

核心问题

我们需要删除最少的字符,使得字符串 s 变得平衡
平衡 的定义:字符串中所有的 'a' 都在所有的 'b' 之前。也就是说,不能出现 ...b...a... 的情况。

这意味着最终的字符串应该是形如 aaaa...abbb...b 的(前面是 i i i 个 'a',后面是 j j j 个 'b',其中 i , j ≥ 0 i, j \ge 0 i,j≥0)。

算法逻辑

这个问题可以转化为:找到一个分割点,使得分割点左边 删除所有的 'b',分割点右边删除所有的 'a',所需的总删除次数最少。

  1. 初始状态:假设分割点在字符串的最左边(即最终字符串全为 'b',没有 'a')。

    • 此时我们需要删除所有的 'a'。
    • 变量 del 初始值就是字符串中 'a' 的总数。
    • 代码巧妙地用 'b' - c 来计算:如果 c 是 'a',则加 1;如果是 'b',加 0。所以初始 del = Count('a')。
  2. 移动分割点

    • 我们将分割点从左向右移动,每次跨过一个字符 c
    • 如果跨过的是 'a'
      • 这个 'a' 从分割点右边(原本需要被删除)变到了左边(现在可以被保留)。
      • 所以删除代价 减 1
    • 如果跨过的是 'b'
      • 这个 'b' 从分割点右边(原本可以保留)变到了左边(现在必须被删除)。
      • 所以删除代价 加 1
    • 合并公式
      • 对于 'a':代价 -1。
      • 对于 'b':代价 +1。
      • 代码公式:del += (c - 'a') * 2 - 1
        • c='a'(0)*2 - 1 = -1
        • c='b'(1)*2 - 1 = 1
  3. 维护最小值

    • 在每次移动分割点后,更新全局最小删除次数 ans

2. 完整代码

java 复制代码
class Solution {
    public int minimumDeletions(String s) {
        // 转换为字符数组,提高遍历效率
        char[] cs = s.toCharArray();
        
        int del = 0;
        
        // 1. 第一遍遍历:计算初始删除代价
        // 假设分割点在最左边,意味着我们要保留右边所有的 'b',删除右边所有的 'a'。
        // 所以初始代价 = 字符串中 'a' 的总数。
        for (char c : cs) {
            // 如果 c 是 'a','b' - 'a' = 1,del 加 1
            // 如果 c 是 'b','b' - 'b' = 0,del 加 0
            del += 'b' - c;
        }
        
        // 初始化最小删除次数 ans
        int ans = del;
        
        // 2. 第二遍遍历:移动分割点
        // 分割点从左向右移动,把字符 c 从"右半部分"移到"左半部分"
        for (char c : cs) {
            // 根据字符类型更新删除代价:
            // c == 'a': 它到了左边被保留(原本在右边被删除),代价 -1
            // c == 'b': 它到了左边被删除(原本在右边被保留),代价 +1
            // 公式 (c - 'a') * 2 - 1 实现了这个逻辑:
            // 'a' -> 0 * 2 - 1 = -1
            // 'b' -> 1 * 2 - 1 = 1
            del += (c - 'a') * 2 - 1;
            
            // 更新全局最小值
            ans = Math.min(del, ans);
        }
        
        return ans;
    }
}

3. 时空复杂度

假设字符串 s 的长度为 N N N。

时间复杂度: O ( N ) O(N) O(N)

  • 计算依据
    • 代码包含两次对字符数组的线性遍历。
    • 第一次计算初始 del,耗时 O ( N ) O(N) O(N)。
    • 第二次动态更新并找最小值,耗时 O ( N ) O(N) O(N)。
  • 结论 : O ( N ) O(N) O(N)。

空间复杂度: O ( N ) O(N) O(N) 或 O ( 1 ) O(1) O(1)

  • 计算依据

    • 如果考虑 toCharArray() 创建的新字符数组,空间为 O ( N ) O(N) O(N)。
    • 如果不考虑输入数据的存储(例如直接使用 s.charAt(i)),则只使用了常数个额外变量,空间为 O ( 1 ) O(1) O(1)。
  • 结论 : O ( N ) O(N) O(N)(因 toCharArray)。

参考灵神

相关推荐
VT.馒头11 小时前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
goodluckyaa11 小时前
LCR 006. 两数之和 II - 输入有序数组
算法
孤狼warrior11 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
Σίσυφος190011 小时前
PCL法向量估计 之 RANSAC 平面估计法向量
算法·机器学习·平面
xhbaitxl11 小时前
算法学习day39-动态规划
学习·算法·动态规划
I_LPL11 小时前
day23 代码随想录算法训练营 回溯专题2
算法·hot100·回溯算法·求职面试
智者知已应修善业11 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
m0_7369191012 小时前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王12 小时前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法