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',所需的总删除次数最少。
-
初始状态:假设分割点在字符串的最左边(即最终字符串全为 'b',没有 'a')。
- 此时我们需要删除所有的 'a'。
- 变量
del初始值就是字符串中 'a' 的总数。 - 代码巧妙地用
'b' - c来计算:如果c是 'a',则加 1;如果是 'b',加 0。所以初始del= Count('a')。
-
移动分割点:
- 我们将分割点从左向右移动,每次跨过一个字符
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。
- 若
- 我们将分割点从左向右移动,每次跨过一个字符
-
维护最小值:
- 在每次移动分割点后,更新全局最小删除次数
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)。
参考灵神