Skip to main content

767. Reorganized String

Original Problem

Sanity Check Is Crucial

The approach isn't difficult. First, count occurrences of each character.

Then perform a time-saving sanity check:

frequency of some charactersum of frequencies of all other characters2\text{frequency of some character} - \text{sum of frequencies of all other characters} \geq 2

If this happens, it's impossible — return "" since no valid rearrangement exists.

How do we set threshold? Let nn be length of string.

When a character's frequency is 1+n2\frac{1 + n}{2}, it's still within the limit.

But if it increases by 12\frac{1}{2} to become 2+n2\frac{2 + n}{2}, the difference becomes 2. A violation.

So sanity check should verify that no character's frequency exceeds 1+n2\frac{1 + n}{2}.

After Passing Sanity Check

Place all characters into a max heap, where each element is in the format (remaining count, character).

As long as max heap has at least two elements:

pop top element (Count1,Char1)(Count_1, Char_1), then pop again to get (Count2,Char2)(Count_2, Char_2).

Use exactly one of each character per round:

append Char1Char_1 and Char2Char_2 to the unfinished reshapedString,

then push (Count11,Char1)(Count_1 - 1, Char_1) back only if Count11>0Count_1 - 1 > 0.

Max heap is only for characters that haven't been exhausted yet.

Same logic applies to (Count21,Char2)(Count_2 - 1, Char_2).

When to Stop ✋🏻

When max heap has 0 or 1 element remaining:

I. If empty, return reshapedString immediately.

II. If one element remains, it must be exactly 1: because sanity check passed.

Append its character to the end of reshapedString and return.

#include <queue>
#include <string>
#include <unordered_map>
using namespace std;

string reorganizeString(string initString) // LeetCode Q.767.
{
unordered_map<char, int> charsCounts;

for (const char& character : initString) {
charsCounts[character]++;

// Sanity check.
if (charsCounts[character] > (initString.size() + 1) / 2)
return "";
}

priority_queue<pair<int, char>> maxHeap; // Format: {count, char}.

for (const auto& [character, count] : charsCounts)
maxHeap.push({count, character});

string reshapedString = "";

while (maxHeap.size() > 1) {
const auto [topOneCount, topOneChar] = maxHeap.top();
maxHeap.pop();

const auto [topTwoCount, topTwoChar] = maxHeap.top();
maxHeap.pop();

reshapedString += topOneChar;
reshapedString += topTwoChar;

if (topOneCount > 1)
maxHeap.push({topOneCount - 1, topOneChar});

if (topTwoCount > 1)
maxHeap.push({topTwoCount - 1, topTwoChar});
}

if (!maxHeap.empty())
reshapedString += maxHeap.top().second;

return reshapedString;
}

Max Heap Efficiency Time complexity: O(nlogk)O(n \log k) where nn is string length and kk is number of distinct characters.

Space complexity: O(n)O(n) where nn is string length.