AlgoMaster Logo

Minimum Deletions to Make String Balanced

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We need to find the minimum number of deletions so that the remaining string has all 'a's on the left and all 'b's on the right. There can be zero 'a's or zero 'b's in the final string, both are valid.

In a balanced string, there is some "split point" where everything to the left is 'a' and everything to the right is 'b'. That split point can sit at the very beginning (all 'b's), the very end (all 'a's), or anywhere in between. For a given split point, we delete all the 'b's on the left side and all the 'a's on the right side.

We want the split point that minimizes total deletions. Counting violations at each split leads to a prefix/suffix approach, and a single running count collapses it to one pass.

Key Constraints:

  • 1 <= s.length <= 10^5 --> With n up to 100,000, we need O(n log n) or better. O(n^2) would be 10 billion operations, far too slow.
  • s[i] is 'a' or 'b' --> Only two characters. This simplifies the problem significantly since we only need to track counts of two values.

Approach 1: Try All Split Points (Brute Force)

Intuition

Enumerate every possible split point. A balanced string has the form aaa...bbb..., so there is some position k (from 0 to n) where everything before k should be 'a' and everything from k onward should be 'b'.

For each split point k, count how many 'b's appear in the left portion (indices 0 to k-1) and how many 'a's appear in the right portion (indices k to n-1). The sum of these two counts is the number of deletions needed for that split. We try all n+1 possible splits and return the minimum.

Algorithm

  1. For each possible split point k from 0 to n (inclusive):
    • Count the number of 'b's in s[0..k-1].
    • Count the number of 'a's in s[k..n-1].
    • Record the total deletions as the sum of these two counts.
  2. Return the minimum total deletions across all split points.

Visualization and Code

Loading animation...

This re-scans the entire string for every split point. Precomputing the counts once makes each split O(1).

Approach 2: Prefix and Suffix Count

Intuition

Instead of re-counting for every split point, precompute the number of 'b's to the left and 'a's to the right using prefix and suffix arrays. Build prefixB[i] = number of 'b's in s[0..i-1], and suffixA[i] = number of 'a's in s[i..n-1]. For split point k, the cost is prefixB[k] + suffixA[k], and we take the minimum over all k. The cost reuses the same definition as the brute force, so the values are identical, but each lookup is now O(1).

Algorithm

  1. Build a prefix array prefixB of size n + 1, where prefixB[i] = number of 'b's in s[0..i-1].
  2. Build a suffix array suffixA of size n + 1, where suffixA[i] = number of 'a's in s[i..n-1].
  3. For each split point k from 0 to n, compute prefixB[k] + suffixA[k].
  4. Return the minimum value.

Visualization and Code

Loading animation...

The time is O(n), but the two arrays cost O(n) extra space. A single running count removes them.

Approach 3: Single Pass DP (Optimal)

Intuition

Scan the string left to right, maintaining bCount, the number of 'b's seen so far. When we reach an 'a', it sits after every 'b' counted so far, which violates the balanced property. There are two ways to resolve every such conflict in the prefix ending here:

  1. Delete this 'a': The cost is deletions + 1, one more than the best cost for the prefix without this character.
  2. Delete all previous 'b's instead: The cost is bCount, the strategy of removing every 'b' seen so far so that this 'a' (and any later 'a') can stay.

Keep a variable deletions holding the minimum deletions that balance the prefix up to the current position. A 'b' adds no new conflict, so it only increments bCount. An 'a' takes the cheaper option: deletions = min(deletions + 1, bCount). This is a space-optimized DP where deletions is the optimal cost for the prefix seen so far.

Algorithm

  1. Initialize deletions = 0 and bCount = 0.
  2. For each character in s:
    • If 'b': increment bCount.
    • If 'a': set deletions = min(deletions + 1, bCount).
  3. Return deletions.

Visualization and Code

Loading animation...