目录
题目:
给你一个字符串 s ,它仅包含字符 'a' 和 'b' 。
你可以删除 s 中任意数目的字符,使得 s 平衡 。
当不存在下标对 (i,j) 满足 i < j ,且 s[i] = 'b' 的同时 s[j]= 'a' ,此时认为 s 是 平衡 的。
请你返回使 s 平衡 的 最少 删除次数。
1、dp 动态规划
思路:
定义f[i]为前i个字符中,使s平衡所删除最小的字符数
则初始化f[0]=0,答案为f[n]
1、如果当前字符是a,则有2个选择:
- 删掉该字符a,即f[i]=f[i-1]+1
- 删掉该字符前面所有的b
也就是 min(f[i-1]+1,b)
2、如果当前字符是b,因为dp保证前面的字符串已经平衡,b在末尾不用删除,只需要统计b的个数即可
class Solution {
public int minimumDeletions(String s) {
int n=s.length();
int[] f=new int[n+1];
f[0]=0;
int b=0;
for(int i=1;i<=n;i++)
if(s.charAt(i-1)=='a') f[i]=Math.min(f[i-1]+1,b);
else
{
f[i]=f[i-1];
b++;
}
return f[n];
}
}
2、枚举分割线取最小
思路:
枚举分割线的位置,分割线前的b要删除,分割线后的a要删除
- 设lb为前缀里要删除的b的个数
- 设ra为在后缀里要删除的a的个数
初始状态分割线在最左端,即整个字符串都是后缀,统计a的个数为删除操作ra
从前往后枚举分割线的位置:
- 遍历到的如果为b,在前缀,要删除,因此lb++
- 遍历到的如果为a,在前缀,则a不用删除,ra--
取使用分割线情况中最小操作次数lb+ra
class Solution {
public int minimumDeletions(String s) {
int n=s.length();
int res=n;
int ra=0,lb=0;
for(int i=0;i<n;i++)
if(s.charAt(i)=='a') ra++; //刚开始分割线在最前面 因此整个字符串都是后缀 后缀的a要删除
for(int i=0;i<n;i++) //移动分割线
{
if(s.charAt(i)=='a') ra--;
res=Math.min(res,ra+lb); // 对于单个'a'和单个'b'需要特判
if(s.charAt(i)=='b') lb++;
}
return res;
}
}