Prerequisites

Before attempting this problem, you should be comfortable with:

  • Hash Maps - Using dictionaries to map characters to their custom ranking or priority
  • Custom Sorting / Comparators - Defining a custom comparison function to sort elements based on non-standard criteria
  • Frequency Counting - Counting occurrences of characters to reconstruct strings in a specific order

1. Custom Comparator

Intuition

We want to reorder string s so that characters appear in the same relative order as they do in order. The key insight is that we can assign each character a rank based on its position in order. Characters not in order can be assigned a high rank (like 26) so they appear at the end. By sorting s using these ranks as the comparison key, characters will naturally arrange themselves according to the custom ordering.

Algorithm

  1. Build a rank map where each character in order maps to its index (0, 1, 2, ...).
  2. For characters not in order, assign a default rank of 26 (higher than any position in order).
  3. Sort the characters of s using the rank values as the sorting key.
  4. Join the sorted characters back into a string and return it.
class Solution:
    def customSortString(self, order: str, s: str) -> str:
        rank = {c: i for i, c in enumerate(order)}
        return ''.join(sorted(s, key=lambda c: rank.get(c, 26)))

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(1)O(1) or O(n)O(n) depending on the sorting algorithm.

2. Frequency Count

Intuition

Instead of sorting, we can build the result string directly by counting character frequencies. Since we know the desired order of characters, we first iterate through order and append each character as many times as it appears in s. Then we handle any remaining characters not in order by iterating through the alphabet. This avoids the O(n log n) sorting overhead.

Algorithm

  1. Create a frequency array of size 26 to count occurrences of each character in s.
  2. Iterate through each character in order. For each character, append it to the result as many times as its count, then set its count to 0.
  3. Iterate through all 26 letters. Append any remaining characters (those not in order) to the result based on their counts.
  4. Return the constructed result string.
class Solution:
    def customSortString(self, order: str, s: str) -> str:
        count = [0] * 26
        for c in s:
            count[ord(c) - ord('a')] += 1

        res = []
        for c in order:
            idx = ord(c) - ord('a')
            while count[idx]:
                res.append(c)
                count[idx] -= 1

        for idx in range(26):
            c = chr(ord('a') + idx)
            while count[idx]:
                count[idx] -= 1
                res.append(c)

        return ''.join(res)

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

Common Pitfalls

Dropping Characters Not Present in Order

Characters in s that do not appear in order must still be included in the result. Forgetting to append these leftover characters produces an incomplete output.

# Wrong: only includes characters from order
for c in order:
    res += c * count[c]
# Missing: characters in s but not in order are lost

# Correct: also append remaining characters
for c in order:
    res += c * count[ord(c) - ord('a')]
    count[ord(c) - ord('a')] = 0
for i in range(26):
    res += chr(ord('a') + i) * count[i]  # Append leftovers

Using Unstable Sort and Expecting Relative Order Preservation

When using a comparison-based sort, characters with the same rank (those not in order) may have their relative order changed. While technically valid per the problem, this can cause confusion. Using a counting approach avoids this issue entirely.

Incorrect Rank Assignment for Missing Characters

Characters not in order need a default rank higher than any position in order. Forgetting to assign a default or using a rank that conflicts with valid positions causes incorrect sorting.

# Wrong: no default rank, causes KeyError
rank = {c: i for i, c in enumerate(order)}
sorted(s, key=lambda c: rank[c])  # Crashes if c not in order

# Correct: provide default rank
sorted(s, key=lambda c: rank.get(c, 26))