If youโre doing your LeetCode daily streak and today you hit Question 1653 โ โMinimum Deletions to Make String Balancedโ, this one is all about turning a messy mix of a and b into a โcleanโ order with the fewest deletions.
Letโs break it down like a human would, not like a textbook.
What does โbalancedโ mean?
Youโre given a string s containing only:
ab
A string is balanced if all a characters come before any b characters.
So these are balanced โ :
"aaaa""aaabbb""bbb"(yes โ noaafterb, so itโs fine)
These are NOT balanced โ:
"ba"(because thereโs abbefore ana)"aababbab"(becauseaappears after someb)
Another way to remember it:
A string is balanced if it has no
"ba"pattern.
Goal
Delete the minimum number of characters (any positions you want) so the final string becomes balanced.
Quick examples
Example 1
Input: s = "aababbab"
Output: 2
You can delete 2 characters to make something like "aaabbb".
Example 2
Input: s = "bbaaaaabb"
Output: 2
Delete two bโs at the start (or some aโs in the middle), and it becomes balanced.
Key insight (the โahaโ moment)
While scanning the string from left to right:
- Every time you see a
b, itโs fine โbcan sit on the right side of a balanced string. - Every time you see an
aafter youโve already seen somebโs, you have a conflict (a"ba"situation).
When that happens, you have only two logical choices:
- Delete this
a
โ cost:deletions + 1 - Delete all previous
bโs (so thisais no longer โafter a bโ)
โ cost:countB(number ofbseen so far)
So at every problematic a, we choose the cheaper option:
deletions = min(deletions + 1, countB)
Thatโs the whole solution.
One-pass Greedy/DP Approach (Best for Interviews)
What we track
countB: how manybโs weโve seen so fardeletions: minimum deletions needed up to the current position
Step-by-step logic
For each character:
- If itโs
'b':countB += 1 - If itโs
'a':deletions = min(deletions + 1, countB)
This works because weโre always keeping the best possible answer for the prefix weโve processed.
Time and space complexity
- Time:
O(n)(single pass) - Space:
O(1)(constant extra memory)
Perfect for large inputs.
Clean code solutions
โ Python (LeetCode-ready)
class Solution:
def minimumDeletions(self, s: str) -> int:
countB = 0
deletions = 0
for ch in s:
if ch == 'b':
countB += 1
else: # ch == 'a'
deletions = min(deletions + 1, countB)
return deletions
โ Java
class Solution {
public int minimumDeletions(String s) {
int countB = 0;
int deletions = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == 'b') {
countB++;
} else { // 'a'
deletions = Math.min(deletions + 1, countB);
}
}
return deletions;
}
}
โ C++
class Solution {
public:
int minimumDeletions(string s) {
int countB = 0;
int deletions = 0;
for (char ch : s) {
if (ch == 'b') {
countB++;
} else { // 'a'
deletions = min(deletions + 1, countB);
}
}
return deletions;
}
};
Mini walkthrough (to make it stick)
Take: s = "ba"
- Start:
countB=0, deletions=0 - See
'b'โcountB=1 - See
'a'โ conflict:- delete
'a'โdeletions + 1 = 1 - delete previous
'b'โcountB = 1 - choose min โ
deletions = 1
- delete
Answer: 1 โ
Common mistakes people make
- Thinking you need to โrebuild the stringโ โ you donโt.
- Using nested loops (goes
O(nยฒ)and can TLE). - Confusing the balanced condition (itโs all
abeforeb, not the other way around).
FAQ
Is this dynamic programming or greedy?
Itโs basically DP compressed into two variables. The update rule is DP-like, but it behaves greedily because we always choose the cheapest fix at each step.
Why is "bbb" balanced even with no a?
Because the rule is only: no a should appear after a b. If there are no aโs, nothing violates that.
Can I solve it with prefix/suffix counts?
Yes. You can compute:
- prefix count of
b - suffix count of
a
and try every split. Itโs stillO(n)but uses extra arrays unless optimized.