AlgoMaster Logo

Special Binary String

hardFrequencyUpdated September 21, 2026

Understanding the Problem

A special binary string has two properties: equal counts of 1s and 0s, and every prefix has at least as many 1s as 0s. This maps directly onto balanced parentheses. Replace every 1 with ( and every 0 with ), and a special binary string becomes a valid balanced parentheses string. The prefix constraint is what prevents an unmatched closing bracket from appearing before its opener.

So "11011000" maps to "(()(()))". Like balanced parentheses, special binary strings have a recursive structure: the string decomposes into top-level groups, and the interior of each group is itself a special binary string. The problem asks us to rearrange these groups through adjacent swaps to produce the lexicographically largest result. Since 1 > 0, we want the 1s as early as possible.

This leaves two questions: what is the optimal arrangement of the top-level groups, and how do we handle the nested structure inside each group?

Key Constraints:

  • 1 <= s.length <= 50 → The string is small, so even an exponential arrangement search over the top-level groups runs in time. A polynomial solution leaves a wide margin.
  • s is guaranteed to be a special binary string → The input needs no validation, and the recursive decomposition always produces valid sub-problems.

Approach 1: Brute Force (Try All Permutations)

Intuition

Identify all the top-level special substrings and try every possible ordering. Swapping adjacent special substrings any number of times lets us produce any permutation of those substrings, since any permutation can be reached through a sequence of adjacent transpositions. So we generate all permutations, concatenate each one, and keep the lexicographically largest.

Each top-level special substring can contain nested special substrings inside it. A complete brute force has to recursively try rearranging the nested substrings at every level too. The number of arrangements grows factorially, but with n up to 50 the number of top-level substrings at any single level stays small enough to enumerate.

Algorithm

  1. Scan through the string, tracking a running balance (add 1 for each '1', subtract 1 for each '0'). Each time the balance returns to 0, mark the boundary of a top-level special substring.
  2. For each top-level special substring, strip the outer '1' and '0', and recursively apply the same process to the interior.
  3. At each recursion level, generate all permutations of the top-level pieces.
  4. For each permutation, concatenate the pieces and track the lexicographically largest result.
  5. Return the largest result found.

Example Walkthrough

1Start: scan s="11011000" tracking balance (1 adds, 0 subtracts)
0
1
i
1
1
2
0
3
1
4
1
5
0
6
0
7
0
1/7

Code

Generating every permutation is wasteful when we only need the largest one. The next approach replaces the permutation search with a single sort.

Approach 2: Recursive Decomposition with Sorting (Optimal)

Intuition

A special binary string decomposes into top-level groups, the same way balanced parentheses do. Each top-level group starts with a 1, ends with a 0, and everything in between is itself a special binary string.

For "11011000", scanning and tracking the balance (increment for 1, decrement for 0) brings the balance back to 0 only at the last character, so the entire string is one top-level group. Strip the outer 1 and 0 and the interior is "101100", which decomposes into two top-level groups: "10" and "1100".

Because adjacent special substrings can be swapped any number of times, the top-level groups can be reordered into any arrangement. Sorting them in descending order produces the largest concatenation. Before sorting, we recursively optimize the interior of each group, so the comparison ranks groups that are already in their best internal form.

The ordering matters: a group's interior must be optimized first, because rearranging the outer groups cannot fix a sub-optimal interior. The outer 1 and 0 of a group never move relative to each other, so each group's internal layout is fixed by its own recursion, and only the sequence of whole groups is free to change.

Algorithm

  1. If the string is empty or has length 2, return it as-is (base case).
  2. Initialize a balance counter to 0 and a start pointer to 0.
  3. Scan through the string character by character. Add 1 to balance for each '1', subtract 1 for each '0'.
  4. Each time balance returns to 0, extract the top-level special substring from start to the current position.
  5. Strip the outer '1' and '0', recursively call the function on the interior.
  6. Store the result as "1" + recursive result + "0".
  7. After scanning the entire string, sort all collected pieces in descending lexicographic order.
  8. Concatenate and return.

Example Walkthrough

1Start: scan s="11011000", balance=0, looking for top-level groups
0
start
1
i
1
1
2
0
3
1
4
1
5
0
6
0
7
0
1/8

Code