AlgoMaster Logo

Reorganize String

Last Updated: April 6, 2026

medium
5 min read

Understanding the Problem

We need to rearrange the characters of a string so that no two identical characters sit next to each other. If that is not possible, we return an empty string.

The first question to ask is: when is it impossible? Consider the string "aaab". We have three as and one b. Even if we place b between two as, we get "aaba" which still has adjacent as. There just are not enough non-a characters to separate all the as.

The key observation is this: if any character appears more than (n + 1) / 2 times (where n is the string length), it is impossible to rearrange. Think of it as placing characters into alternating slots. For a string of length n, the even positions (0, 2, 4, ...) can hold at most ceil(n/2) characters. If the most frequent character exceeds that count, it must spill into adjacent positions, violating the constraint.

Key Constraints:

  • 1 <= s.length <= 500 → With n up to 500, even O(n^2) solutions run comfortably. But we can do O(n).
  • s consists of lowercase English letters → Only 26 possible characters. This is a constant we can exploit.

Approach 1: Sorting by Frequency

Intuition

The most natural first thought: if we want to spread characters apart, we should deal with the most frequent characters first. They are the hardest to place since they need the most "breathing room."

Here is the idea. Sort all characters by their frequency in descending order. Then fill them into the result array at even indices first (0, 2, 4, ...), and once those are full, continue at odd indices (1, 3, 5, ...). Since we process characters from most frequent to least frequent, the dominant character gets placed at even positions where no two are adjacent. The remaining characters fill in the gaps.

Before doing any of this, we check the impossibility condition: if any character appears more than (n + 1) / 2 times, return "".

Algorithm

  1. Count the frequency of each character in the string.
  2. Check if any frequency exceeds (n + 1) / 2. If so, return "".
  3. Create a list of characters sorted by frequency in descending order. Each character appears as many times as its frequency.
  4. Fill the result array: place characters at indices 0, 2, 4, ..., then 1, 3, 5, ...
  5. Return the result as a string.

Example Walkthrough

result
1Frequencies: a=3, b=2, c=1. Sorted: [a, a, a, b, b, c]. Start filling at idx=0.
0
idx
1
2
3
4
5
1/7

Code

The sorting step here is O(k log k) where k = 26, which is effectively constant. But what if we want a more flexible approach that does not rely on filling even/odd indices? The max heap approach gives us a more intuitive greedy strategy: at each step, pick the most frequent character that is different from the one we just placed.

Approach 2: Max Heap (Greedy)

Intuition

Instead of pre-sorting and filling indices, what if we built the string one character at a time, always choosing the best character to place next?

The greedy insight: at each position, place the character with the highest remaining frequency, as long as it is not the same as the character we just placed. This maximizes our options going forward. If we always "use up" the most common character whenever we can, we avoid a situation where we are stuck with too many copies of one character at the end.

Here is the trick that makes this work cleanly with a heap: after placing a character, do not push it back into the heap immediately. Hold it aside for one round. On the next iteration, push it back (with decremented count) before popping the next character. This "hold one back" mechanism guarantees we never place the same character twice in a row.

Algorithm

  1. Count the frequency of each character.
  2. Check if any frequency exceeds (n + 1) / 2. If so, return "".
  3. Build a max heap with entries (frequency, character).
  4. Initialize prev as null (no previous character yet).
  5. While the heap is not empty:
    • Pop the character with the highest frequency.
    • Append it to the result.
    • If prev still has remaining count, push it back into the heap.
    • Set prev to the current character (with decremented count).
  6. Return the result.

Example Walkthrough

result
1Heap: [(3,a), (2,b), (1,c)]. prev = null.
0
pos
1
2
3
4
5
maxHeap
1Heap: [(3,a), (2,b), (1,c)]
(3,a)(2,b)(1,c)
1/7

Code

The heap approach is elegant and generalizable, but we are maintaining a heap for at most 26 characters. Can we skip the heap entirely? If we just count frequencies and fill indices directly, we avoid both sorting and heap operations, reaching a truly simple O(n) solution.

Approach 3: Frequency Count + Index Filling (Optimal)

Intuition

Here is the simplest way to think about this problem. We have a result array with positions 0 through n-1. If we fill positions 0, 2, 4, ... first and then 1, 3, 5, ..., any two consecutive characters we place are two indices apart in the result. They can never be adjacent.

So the strategy is dead simple:

  1. Find the most frequent character.
  2. Place it at even indices first (since it needs the most room).
  3. Fill all remaining characters in the remaining positions, continuing the even-then-odd pattern.

The only constraint is that the most frequent character must fit within the even positions (plus possibly wrapping to some odd positions). This is guaranteed as long as its frequency does not exceed (n + 1) / 2.

Algorithm

  1. Count the frequency of each character.
  2. Find the character with the maximum frequency.
  3. If max frequency exceeds (n + 1) / 2, return "".
  4. Place the most frequent character at indices 0, 2, 4, ... until its count is exhausted.
  5. Continue placing remaining characters at the current index, wrapping from even to odd indices when even indices are filled.
  6. Return the result.

Example Walkthrough

result
1Frequencies: a=3, b=2, c=1. Max freq char = 'a' (3). (6+1)/2 = 3. Valid.
0
idx
1
2
3
4
5
1/7

Code