Reorganize String solution and explanation
9 more videos on this problem
Reorganize StringKevin Naughton Jr. · 12:44 · 79K views
Reorganize String - Tesla Interview Question - Leetcode 767 - PythonNeetCode · 15:52 · 78K views
Reorganize String (LeetCode 767) | Full solution with scenario breakdown for easy explanationNikhil Lohia · 16:00 · 19K views
Reorganize String - LeetCode 767 - Python #leetcode #string #interviewquestion #greedyDeepti Talesra · 14:12 · 6K views
REORGANIZE STRING | LEETCODE # 767 | PYTHON HEAP SOLUTIONCracking FAANG · 11:58 · 4K views
LeetCode 767 (ReOrganize - String)MyCodingBuddy · 8:40 · 3K views
LeetCode 767. Reorganize String Like a Pro | Deep Dive into Priority Queue and Sorting TechniquesvanAmsen · 8:17 · 2K views
[Java] Leetcode 767. Reorganize String [Greedy #1]Eric Programming · 14:36 · 2K views
Reorganize String - Leetcode 767 - PythonTechError · 6:03 · 1K views
767. Reorganize String (Leetcode Medium)Programming Live with Larry · 10:28 · 665 views
The problem
Given a string s, rearrange the characters of s so that any two adjacent characters are not the same.
Return any possible rearrangement of s or return "" if not possible.
Example 1:
Input: s = "aab" Output: "aba"
Example 2:
Input: s = "aaab" Output: ""
Constraints:
1 <= s.length <= 500sconsists of lowercase English letters.
Approach overview
Problem Overview: You are given a string and must rearrange its characters so that no two adjacent characters are the same. If such an arrangement is impossible, return an empty string. The core challenge is distributing high-frequency characters so they never appear next to each other.
Approach 1: Greedy Heap Approach (O(n log k) time, O(k) space)
This method uses a heap (priority queue) to always pick the two characters with the highest remaining frequency. First count character frequencies using a hash table. Push each character and its count into a max heap. Repeatedly pop the top two characters, append them to the result, decrease their counts, and push them back if they still have remaining occurrences. Because the two most frequent characters are placed apart each step, adjacent duplicates never occur. The heap ensures we always use the most constrained characters first, which prevents situations where a high-frequency character gets stuck at the end. This approach works well when you want a straightforward greedy solution and is commonly used in interview explanations.
Approach 2: Counting and Greedy Placement (O(n) time, O(k) space)
This optimized approach relies on frequency counting and careful placement instead of a heap. Count occurrences of each character, then sort or identify the character with the highest frequency. Place this character at even indices (0, 2, 4, ...) of the result array first. After its occurrences are exhausted, fill the remaining positions with the other characters. The key insight is that spreading the most frequent character across even positions guarantees separation as long as its count does not exceed (n + 1) / 2. If it does, no valid arrangement exists. This technique leverages greedy placement and simple counting, reducing the complexity from heap operations to linear iteration. Many competitive programmers prefer this method because it achieves O(n) time with minimal overhead.
Recommended for interviews: The greedy heap solution is the most intuitive explanation during interviews because it clearly shows how you prioritize the most frequent characters and maintain separation. The counting-based greedy placement demonstrates deeper optimization and achieves linear time. Showing the heap approach first and then mentioning the O(n) counting optimization signals strong algorithmic reasoning.
Approach 1: Greedy Heap Approach
This approach utilizes a max heap to always place the character with the maximum frequency next, ensuring that no two adjacent characters are the same. If the character frequency is more than half of the string length, it is impossible to rearrange.
import heapq
from collections import Counter
def reorganize_string(s: str) -> str:
freq = Counter(s)
max_heap = [(-count, char) for char, count in freq.items()]
heapq.heapify(max_heap)
prev_count, prev_char = 0, ''
result = []
while max_heap:
count, char = heapq.heappop(max_heap)
result.append(char)
if prev_count < 0:
heapq.heappush(max_heap, (prev_count, prev_char))
prev_count, prev_char = count + 1, char
if len(result) != len(s):
return ""
return "".join(result)import java.util.PriorityQueue;
import java.util.HashMap;
public class ReorganizeString {
public String reorganizeString(String s) {
HashMap<Character, Integer> frequencyMap = new HashMap<>();
for (char c : s.toCharArray()) {
frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
}
PriorityQueue<Character> maxHeap = new PriorityQueue<>((a, b) -> frequencyMap.get(b) - frequencyMap.get(a));
maxHeap.addAll(frequencyMap.keySet());
StringBuilder result = new StringBuilder();
while (maxHeap.size() > 1) {
char first = maxHeap.remove();
char second = maxHeap.remove();
result.append(first);
result.append(second);
frequencyMap.put(first, frequencyMap.get(first) - 1);
frequencyMap.put(second, frequencyMap.get(second) - 1);
if (frequencyMap.get(first) > 0) maxHeap.add(first);
if (frequencyMap.get(second) > 0) maxHeap.add(second);
}
if (!maxHeap.isEmpty()) {
char last = maxHeap.remove();
if (frequencyMap.get(last) > 1) return "";
result.append(last);
}
return result.toString();
}
}In this solution, we utilize Python's heapq library to simulate a max heap by storing negative frequencies. We arrange the highest frequency characters first and reinsert them with decremented counts after placing another character, ensuring no two adjacent characters are the same.
Time Complexity: O(n log k) where n is the length of the string and k is the number of unique characters. Space Complexity: O(n)
Approach 2: Counting and Greedy Approach
This approach utilizes a direct counting mechanism and attempts to place characters in a greedy manner, utilizing an array to keep track of placement positions for the most frequent characters first.
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string reorganizeString(string s) {
vector<int> count(26, 0);
int n = s.size();
for (char c : s) count[c - 'a']++;
int maxCount = *max_element(count.begin(), count.end());
if (maxCount > (n + 1) / 2) return "";
string result(n, ' ');
int evenIndex = 0, oddIndex = 1;
for (int i = 0; i < 26; i++) {
while (count[i] > 0 && count[i] <= n / 2 && oddIndex < n) {
result[oddIndex] = 'a' + i;
oddIndex += 2;
count[i]--;
}
while (count[i] > 0) {
result[evenIndex] = 'a' + i;
evenIndex += 2;
count[i]--;
}
}
return result;
}#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reorganizeString(char* s) {
int n = strlen(s);
int count[26] = {0};
for (int i = 0; i < n; i++)
count[s[i] - 'a']++;
int maxCount = 0, letter = 0;
for (int i = 0; i < 26; i++) {
if (count[i] > maxCount) {
maxCount = count[i];
letter = i;
}
}
if (maxCount > (n + 1) / 2) return "";
char* result = (char*)malloc((n + 1) * sizeof(char));
result[n] = '\0';
int index = 0;
while (count[letter]--) {
result[index] = letter + 'a';
index += 2;
}
for (int i = 0; i < 26; i++) {
while (count[i]--) {
if (index >= n) index = 1;
result[index] = i + 'a';
index += 2;
}
}
return result;
}This C++ solution checks the most frequent character and begins placing it at even indices. Remaining characters fill in, prioritizing even indices before odd ones.
Time Complexity: O(n). Space Complexity: O(1) with fixed-size storage.
Approach 3: Default Approach
func reorganizeString(s string) string {
cnt := make([]int, 26)
for _, c := range s {
t := c - 'a'
cnt[t]++
}
mx := slices.Max(cnt)
n := len(s)
if mx > (n+1)/2 {
return ""
}
m := [][]int{}
for i, v := range cnt {
if v > 0 {
m = append(m, []int{v, i})
}
}
sort.Slice(m, func(i, j int) bool {
return m[i][0] > m[j][0]
})
ans := make([]byte, n)
k := 0
for _, e := range m {
v, i := e[0], e[1]
for v > 0 {
ans[k] = byte('a' + i)
k += 2
if k >= n {
k = 1
}
v--
}
}
return string(ans)
}use std::collections::{BinaryHeap, HashMap, VecDeque};
impl Solution {
#[allow(dead_code)]
pub fn reorganize_string(s: String) -> String {
let mut map = HashMap::new();
let mut pq = BinaryHeap::new();
let mut ret = String::new();
let mut queue = VecDeque::new();
let n = s.len();
// Initialize the HashMap
for c in s.chars() {
map.entry(c)
.and_modify(|e| {
*e += 1;
})
.or_insert(1);
}
// Initialize the binary heap
for (k, v) in map.iter() {
if 2 * *v - 1 > n {
return "".to_string();
} else {
pq.push((*v, *k));
}
}
while !pq.is_empty() {
let (v, k) = pq.pop().unwrap();
ret.push(k);
queue.push_back((v - 1, k));
if queue.len() == 2 {
let (v, k) = queue.pop_front().unwrap();
if v != 0 {
pq.push((v, k));
}
}
}
if ret.len() == n {
ret
} else {
"".to_string()
}
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Greedy Heap Approach | Time Complexity: O(n log k) where n is the length of the string and k is the number of unique characters. Space Complexity: O(n) |
| Counting and Greedy Approach | Time Complexity: O(n). Space Complexity: O(1) with fixed-size storage. |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Greedy Heap (Priority Queue) | O(n log k) | O(k) | General solution that works for any character distribution and is easy to reason about in interviews |
| Counting + Greedy Placement | O(n) | O(k) | Best when optimizing for linear time using frequency counting and index placement |
Frequently asked questions
Is Reorganize String easy or hard?
Reorganize String is generally classified as a medium difficulty problem. The challenge lies in recognizing the greedy pattern and correctly handling character frequencies to prevent adjacent duplicates.
Reorganize String Python/Java solution
Python and Java solutions commonly implement a max heap using heapq (with negative counts) in Python or PriorityQueue in Java. The algorithm repeatedly pops the two highest-frequency characters, appends them to the result, and pushes them back if their counts remain.
How to solve Reorganize String in O(n)?
Use a frequency array to count characters, then place the character with the highest frequency at even indices of the result array (0, 2, 4...). Once its count is exhausted, fill the remaining positions with other characters. This works as long as the maximum frequency does not exceed (n + 1) / 2, otherwise a valid arrangement is impossible.
What is the best approach for Reorganize String?
The most common approach uses a greedy strategy with a max heap (priority queue). Characters are stored by frequency, and the two most frequent characters are placed alternately to avoid adjacent duplicates. This method runs in O(n log k) time where k is the number of distinct characters and is widely accepted in coding interviews.
Is Reorganize String asked at Google/Amazon/Meta?
Reorganize String is a common greedy and heap interview problem that has appeared in coding interviews at companies such as Amazon, Google, and Meta. Interviewers use it to evaluate understanding of priority queues, frequency counting, and greedy decision making.
What data structure is used in Reorganize String?
The typical solution uses a max heap (priority queue) to repeatedly select the characters with the highest remaining frequency. A hash map or array is used for counting frequencies before pushing them into the heap.
What is the time complexity of Reorganize String?
The heap-based greedy solution runs in O(n log k) time because each insertion and removal from the priority queue costs log k. An optimized counting and greedy placement approach can achieve O(n) time by placing the most frequent character at even indices and filling the remaining characters afterward.
