🧵Reorganize String

Question (LC.767)

Given a string s, rearrange the characters of s so that no same characters are adjacent to each other.

Examples

I: s = "aab"
O: "aba"
I: s = "aaab"
O: "" no solution 
I: s = "aabb"
O: "abab", "baba" multiple solutions 

Brute Force

Generate all permutations, check if one of them is a valid rearrangement.

Guarantee to work in EXP time. Length really matters in this case. < 20 will kind of work.

Code

from itertools import permutations 

def reorganize_string(self, s: str) -> str:
    if len(s) <= 1:
        return s
    # permutations yields next permuation in sorted order 
    for perm in permutations(s):
        if self.is_not_adj(perm):
            return "".join(perm)

    return ""

def is_not_adj(self, p_list) -> bool:
    if len(p_list) < 1:
        return True
    for i in range(len(p_list) - 1):
        if p_list[i] == p_list[i+1]:
            return False
    return True

Passed 26 / 71

Time Limit Exceeded on s = "kkkkzrkatkwpkkkktrq"

A Better Approach

We want to bring down the time complexity to polynomial time. One intuitive solution is to group the letters, sort by frequency, and then do an insertion sort for each letter starting from the end.

For example,

The initial grouping and sorting by frequency guarantees an initial state that is solvable within n moves. No insertion sort operation should be wasted if starting in this initial state. If one insertion sort cannot find a valid place to insert the last element, then the input is unsolvable.

The proof of correctness is not immediately apparent. We can try out a few examples to validate this approach.

The motivation of having this initial set up and inserting the last element is to maximize the number of valid positions per insertion. We'll explore that part a bit more later.

Code

This code is accepted with 102ms runtime. The initial grouping and sorting can be O(nlogn). The insertion sort is O(n^2).

Heap Approach

To do better than O(n^2), we have to evaluate solutions that are O(nlogn) or O(n). We can achieve O(nlogn) with heap.

Code

Worst case O(nlogk) + O(2nlogk) which is just O(nlogk). 24ms beats 99.12%.

Last updated