1. 问题描述:
给你一个字符串 s ,它仅包含字符 'a' 和 'b' 。你可以删除 s 中任意数目的字符,使得 s 平衡 。我们称 s 平衡的当不存在下标对 (i,j) 满足 i < j 且 s[i] = 'b' 同时 s[j]= 'a' 。请你返回使s平衡的最少删除次数。
示例 1:
输入:s = "aababbab"
输出:2
解释:你可以选择以下任意一种方案:
下标从 0 开始,删除第 2 和第 6 个字符("aababbab" -> "aaabbb"),
下标从 0 开始,删除第 3 和第 6 个字符("aababbab" -> "aabbbb")。
示例 2:
输入:s = "bbaaaaabb"
输出:2
解释:唯一的最优解是删除最前面两个字符。
提示:
1 <= s.length <= 105
s[i]
要么是'a'
要么是'b'
。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-deletions-to-make-string-balanced
2. 思路分析:
① 分析题目可以知道比较容易想到的是:我们需要求解出0到当前位置p中字符a的数目与当前位置p到字符串结束位置的b的数目,两个数目相加表示的是不用删除的数目count,使用字符串总的长度减去count那么就是答案了,所以我们需要先遍历字符串,使用两个数组分别记录0到当前位置p的a的数目与p到字符串末尾的数目,最后再遍历这两个数组,将对应位置相加取得最大值max, 最后返回len(s) - max即可
② 其中①中的方法是比较容易想到的,除了上面的方法之外,在力扣的题解中发现了思路不错的两种解法,第一种解法是使用分析的方法,题解网址,感觉里面的思路还是很巧妙的,第二种思路是动态规划的解法,题解网址,其中使用到了二维的dp来解决,dp[x][0] 表示以"a" 结尾的最小修改次数,dp[x][1] 表示以"b" 结尾的最小修改次数
3. 代码如下:
class Solution:
def minimumDeletions(self, s: str) -> int:
n = len(s)
a, b = [0] * (n + 1), [0] * (n + 1)
for i in range(n):
if s[i] == "a":
a[i + 1] = a[i] + 1
else:
a[i + 1] = a[i]
if s[n - 1 - i] == "b":
b[n - 1 - i] = b[n - i] + 1
else:
b[n - 1 - i] = b[n - i]
res = 0
for i in range(1, n + 1):
res = max(a[i] + b[i - 1], res)
return n - res
分析:
class Solution:
def minimumDeletions(self, s: str) -> int:
count, dp = 0, 0
for c in s:
if c == "a":
if count != dp:
dp += 1
else:
count += 1
return dp
动态规划:
class Solution:
# 动态规划思路
def minimumDeletions(self, s: str) -> int:
n = len(s)
dp = [[0] * 2 for i in range(n + 1)]
for i in range(n):
if s[i] == "a":
# 当前位置i之前以a结尾最少修改次数
dp[i + 1][0] = dp[i][0]
# 当前位置i之前以b结尾最少修改次数, 删除当前的a
dp[i + 1][1] = dp[i][1] + 1
else:
# 当前位置i之前以a结尾最少修改次数, 删除b
dp[i + 1][0] = dp[i][0] + 1
# 不用删除取以a结尾, b结尾的最少的修改次数
dp[i + 1][1] = min(dp[i][0], dp[i][1])
return min(dp[n][0], dp[n][1])