Skip to main content
Reorganize / Schedule

Reorganize String

To rearrange a string so no two adjacent characters are the same: always place the most frequent character next. Use a max-heap by frequency. After placing a character, reduce its count and hold it out for one round.

O(n log n)
·
O(n)

How It Works

Reorganize String spreads characters so no two identical ones are adjacent, driven by a max-heap of character frequencies. Always place the most frequent remaining character — the one under the greatest scheduling pressure — but never the same character twice in a row. The mechanics: pop the top character, append it to the output, decrement its count, and hold it aside for one round while the next pop takes its place; then push the held character back if it still has occurrences left.

Feasibility has a clean test up front: if any character's count exceeds ceil(n/2), placement is impossible because there are not enough gaps to separate the copies. Each of the n placements does O(1) heap operations at O(log A) each — A being the alphabet size, at most 26 — so the total is O(n log A), effectively linear. Greedily relieving the biggest pile first is exactly what prevents dead ends.

Step-by-Step Visualization

Reorganize 'aaabb' → no adjacent duplicates
a
0
a
1
a
2
b
3
b
4
Freqa:3, b:2
1/3

Code

Java
static String reorganizeString(String s) {
  int[] freq = new int[26];
  for (char c : s.toCharArray()) freq[c - 'a']++;

  PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[1] - a[1]);
  for (int i = 0; i < 26; i++) if (freq[i] > 0) pq.add(new int[]{i, freq[i]});
  if (pq.peek()[1] > (s.length() + 1) / 2) return "";

  StringBuilder result = new StringBuilder();
  while (pq.size() > 1) {
    int[] first = pq.poll(), second = pq.poll();
    result.append((char)('a' + first[0]));
    result.append((char)('a' + second[0]));
    if (--first[1] > 0) pq.add(first);
    if (--second[1] > 0) pq.add(second);
  }
  if (!pq.isEmpty()) result.append((char)('a' + pq.poll()[0]));
  return result.toString();
}

Tips & Gotchas

1Greedy: always place the most frequent character next
2Use a max-heap to efficiently find the most frequent
3Hold back the just-placed character for one turn

Practice Problems

  • 1Reorganize String
  • 2Task Scheduler
  • 3Distant Barcodes
  • 4Rearrange String k Distance Apart

About the Reorganize / Schedule Pattern

Use a max-heap to always process the most frequent item first. After processing, apply a cooldown before it can be used again. This greedy approach minimizes idle gaps or spreads characters apart.

Key insight

Need the K largest? Use a min-heap of size K — anything larger than the min gets in. For median, split into two heaps: max-heap for lower half, min-heap for upper half.

Common Heap Interview Problems

  • Kth Largest Element
  • Top K Frequent Elements
  • Find Median from Data Stream
  • Merge K Sorted Lists
  • Task Scheduler
  • K Closest Points to Origin

Frequently Asked Questions

Why always place the most frequent character first?

The most frequent character has the fewest remaining slots that can legally host it, so deferring it risks reaching a state where its copies must sit adjacent. Placing it greedily whenever allowed keeps the frequency distribution as flat as possible, which is provably safe when the ceil(n/2) feasibility condition holds.

Is there a way to solve this without a heap?

Yes — count frequencies, then fill the result's even indices (0, 2, 4, ...) with the most frequent character first, wrapping to odd indices when the even ones run out. This O(n + A) interleaving trick achieves the same separation, though the heap version generalizes more easily to k-distance variants.