Talentd
FleetCode
Make and follow sheets.Sign in

Rearrange String k Distance Apart solution and explanation

HardCountingGreedyHash TableHeap (Priority Queue)4 min read39.9% acceptanceUpdated 23 Mar 2026Premium elsewhere, free here
LeetCode 358. Rearrange String k Distance Apart Explanation and Solutionhappygirlzt · 11:36 · 3K viewsWatch on YouTube
9 more videos on this problem
  1. LeetCode 358. Rearrange String k Distance Apart Explanation and Solutionhappygirlzt · 11:36 · 3K views
  2. LeetCode 358. Rearrange String k Distance ApartHappy Coding · 23:55 · 2K views
  3. LeetCode 358. Rearrange String k Distance Apart 中文解释 Chinese Versionhappygirlzt · 14:36 · 1K views
  4. 358. Rearrange String k Distance Apart || LeetCode || Competitive Programming || Hard ProblemAshish Mishra · 12:27 · 1K views
  5. LeetCode 358. Rearrange String k Distance Apart - Google Interview QuestionCode with Carter · 17:45 · 1K views
  6. 【每日一题】358. Rearrange String k Distance Apart, 7/29/2020Huifeng Guan · 21:56 · 943 views
  7. Leetcode 358. Rearrange String k Distance Apart | C++Unofficial Sendoh · 10:26 · 330 views
  8. 358. Rearrange String k Distance Apart - Week 2/5 Leetcode September ChallengeProgramming Live with Larry · 1:35:37 · 279 views
  9. Leetcode Question 358: Rearrange String k Distance ApartFMVP · 9:23 · 216 views
  10. 358. Rearrange String k Distance Apart - Week 3/4 Leetcode February ChallengeProgramming Live with Larry · 46:24 · 148 views

The problem

Given a string s and an integer k, rearrange s such that the same characters are at least distance k from each other. If it is not possible to rearrange the string, return an empty string "".

Example 1:

Input: s = "aabbcc", k = 3
Output: "abcabc"
Explanation: The same letters are at least a distance of 3 from each other.

Example 2:

Input: s = "aaabc", k = 3
Output: ""
Explanation: It is not possible to rearrange the string.

Example 3:

Input: s = "aaadbbcc", k = 2
Output: "abacabcd"
Explanation: The same letters are at least a distance of 2 from each other.

Constraints:

  • 1 <= s.length <= 3 * 105
  • s consists of only lowercase English letters.
  • 0 <= k <= s.length

Approach overview

Problem Overview: You are given a string s and an integer k. Rearrange the characters so that the same characters appear at least k distance apart. If such an arrangement is impossible, return an empty string. The challenge is balancing character frequency while respecting the spacing constraint.

Approach 1: Greedy Placement with Sorting (O(n^2) time, O(n) space)

Count the frequency of each character using a hash table. Repeatedly pick the character with the highest remaining frequency that does not violate the k-distance rule. Each placement requires scanning previously used characters or maintaining a temporary blocked set until the cooldown expires. Because the algorithm repeatedly searches for the next valid character, the selection step can degrade to O(n) per placement, leading to O(n^2) time. This approach demonstrates the greedy idea but becomes inefficient for large inputs.

Approach 2: Greedy + Max Heap + Cooldown Queue (O(n log σ) time, O(σ) space)

The optimal strategy uses a max heap (priority queue) to always place the character with the highest remaining frequency. First compute frequencies with a hash map. Push characters into a max heap ordered by remaining count. Each step pops the most frequent character, appends it to the result, and decreases its count.

To enforce the k spacing rule, push the used character into a cooldown queue with the index when it can be used again (current_index + k). While building the string, check the queue front; once its cooldown expires, push that character back into the heap. This guarantees that a character cannot reappear before k positions pass.

The greedy insight: always place the most frequent available character. High-frequency characters are the hardest to distribute; scheduling them early avoids dead ends later. Heap operations cost O(log σ) where σ is the number of unique characters, so building the result takes O(n log σ) time.

Recommended for interviews: Interviewers typically expect the greedy heap solution. A brute-force greedy attempt shows you understand the spacing constraint, but the max heap with cooldown queue demonstrates mastery of greedy scheduling and priority queues. It cleanly enforces the distance rule while always choosing the best next character.

Solution

We use a hash table or array cnt to count the occurrences of each character in the string. Then, we use a max heap pq to store each character and its count. Each element in the heap is a tuple (v, c), where v is the count and c is the character.

When rearranging the string, we repeatedly pop the top element (v, c) from the heap, add character c to the result string, and push (v-1, c) into a queue q. When the length of the queue q reaches k or more, we pop the front element; if its v is greater than 0, we push it back into the heap. Repeat this process until the heap is empty.

Finally, we check whether the length of the result string equals the original string. If so, we return the result string; otherwise, we return an empty string.

The time complexity is O(n log n), where n is the length of the string. The space complexity is O(|\Sigma|), where |\Sigma| is the size of the character set, which is 26 in this problem.

Related problems:

class Solution:
    def rearrangeString(self, s: str, k: int) -> str:
        cnt = Counter(s)
        pq = [(-v, c) for c, v in cnt.items()]
        heapify(pq)
        q = deque()
        ans = []
        while pq:
            v, c = heappop(pq)
            ans.append(c)
            q.append((v + 1, c))
            if len(q) >= k:
                e = q.popleft()
                if e[0]:
                    heappush(pq, e)
        return "" if len(ans) < len(s) else "".join(ans)
class Solution {
    public String rearrangeString(String s, int k) {
        int[] cnt = new int[26];
        for (char c : s.toCharArray()) {
            ++cnt[c - 'a'];
        }
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[0] - a[0]);
        for (int i = 0; i < cnt.length; ++i) {
            if (cnt[i] > 0) {
                pq.offer(new int[] {cnt[i], i});
            }
        }
        Deque<int[]> q = new ArrayDeque<>();
        StringBuilder ans = new StringBuilder();
        while (!pq.isEmpty()) {
            var p = pq.poll();
            p[0] -= 1;
            ans.append((char) ('a' + p[1]));
            q.offerLast(p);
            if (q.size() >= k) {
                p = q.pollFirst();
                if (p[0] > 0) {
                    pq.offer(p);
                }
            }
        }
        return ans.length() < s.length() ? "" : ans.toString();
    }
}
class Solution {
public:
    string rearrangeString(string s, int k) {
        vector<int> cnt(26, 0);
        for (char c : s) {
            ++cnt[c - 'a'];
        }

        priority_queue<pair<int, int>> pq;
        for (int i = 0; i < 26; ++i) {
            if (cnt[i] > 0) {
                pq.emplace(cnt[i], i);
            }
        }

        queue<pair<int, int>> q;
        string ans;
        while (!pq.empty()) {
            auto p = pq.top();
            pq.pop();
            p.first -= 1;
            ans.push_back('a' + p.second);
            q.push(p);
            if (q.size() >= k) {
                p = q.front();
                q.pop();
                if (p.first > 0) {
                    pq.push(p);
                }
            }
        }

        return ans.size() < s.size() ? "" : ans;
    }
};
export function rearrangeString(s: string, k: number): string {
    const cnt: number[] = Array(26).fill(0);
    for (const c of s) {
        cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    }

    const pq = new PriorityQueue<[number, number]>((a, b) => b[0] - a[0]);
    for (let i = 0; i < 26; i++) {
        if (cnt[i] > 0) {
            pq.enqueue([cnt[i], i]);
        }
    }

    const q: [number, number][] = [];
    const ans: string[] = [];
    while (!pq.isEmpty()) {
        const [count, idx] = pq.dequeue()!;
        const newCount = count - 1;
        ans.push(String.fromCharCode('a'.charCodeAt(0) + idx));
        q.push([newCount, idx]);
        if (q.length >= k) {
            const [frontCount, frontIdx] = q.shift()!;
            if (frontCount > 0) {
                pq.enqueue([frontCount, frontIdx]);
            }
        }
    }
    return ans.length < s.length ? '' : ans.join('');
}
func rearrangeString(s string, k int) string {
	cnt := [26]int{}
	for _, c := range s {
		cnt[c-'a']++
	}
	pq := priorityqueue.NewWith(func(a, b any) int {
		x := a.([2]int)
		y := b.([2]int)
		return y[0] - x[0]
	})

	for i := 0; i < 26; i++ {
		if cnt[i] > 0 {
			pq.Enqueue([2]int{cnt[i], i})
		}
	}

	var q [][2]int
	var ans strings.Builder

	for pq.Size() > 0 {
		p, _ := pq.Dequeue()
		pair := p.([2]int)
		pair[0]--
		ans.WriteByte(byte('a' + pair[1]))
		q = append(q, pair)

		if len(q) >= k {
			front := q[0]
			q = q[1:]
			if front[0] > 0 {
				pq.Enqueue(front)
			}
		}
	}

	if ans.Len() < len(s) {
		return ""
	}
	return ans.String()
}
Try this approach in the editor

Complexity analysis

ApproachTimeSpaceWhen to Use
Greedy Placement with Repeated ScanningO(n^2)O(n)Useful for understanding the constraint and basic greedy idea, but inefficient for large inputs
Greedy + Max Heap + Cooldown QueueO(n log σ)O(σ)General optimal solution when characters have different frequencies and spacing constraints must be enforced

Frequently asked questions

Is Rearrange String k Distance Apart easy or hard?

Rearrange String k Distance Apart is classified as a Hard problem because it combines greedy scheduling with heap management and constraint enforcement. The tricky part is ensuring characters re-enter the heap only after k positions have passed.

Rearrange String k Distance Apart Python/Java solution

Most implementations follow the same structure across languages: count characters with a map, push them into a max heap ordered by frequency, then maintain a queue storing characters until their cooldown expires. Python uses heapq with negative counts, while Java uses PriorityQueue with a custom comparator.

How to solve Rearrange String k Distance Apart in O(n)?

Strict O(n) is generally not achievable because the algorithm needs a priority structure to select the most frequent character. With a fixed alphabet (for example only lowercase letters), the heap size is bounded by 26, making the effective complexity close to O(n). In practice the max heap + cooldown queue solution behaves nearly linear.

What is the best approach for Rearrange String k Distance Apart?

The most effective approach uses a greedy strategy with a max heap and a cooldown queue. A hash map counts character frequencies, the max heap always selects the most frequent available character, and the cooldown queue prevents reuse until k positions pass. This ensures valid spacing while keeping time complexity at O(n log σ), where σ is the number of distinct characters.

Is Rearrange String k Distance Apart asked at Google/Amazon/Meta?

This problem appears in interview prep sets for companies like Google, Amazon, and Meta because it tests greedy reasoning and priority queue usage. Candidates must manage frequency counts and scheduling constraints simultaneously, which is a common systems-style allocation pattern.

What data structure is used in Rearrange String k Distance Apart?

The core data structures are a hash table for counting frequencies, a max heap (priority queue) for selecting the next character with the highest remaining count, and a queue to track characters during their k-length cooldown window.

What is the time complexity of Rearrange String k Distance Apart?

The optimal solution runs in O(n log σ) time and O(σ) space. Each character insertion and removal from the max heap costs O(log σ), and this happens once per character while constructing the result string.

Comments

Now write it yourselfClose this page and solve Rearrange String k Distance Apart in the editor, without looking.
Practise Rearrange String k Distance Apart