Custom Sort String
Table of Contents + β
Custom Sort String looks odd the first time you read it. You do not sort by A to Z. You sort by a rule that someone else gives you. So the interviewer wants to see if you can follow a custom order instead of the normal one. That small twist trips up a lot of people.
π― The Problem
You get two strings and you rearrange the second to match the order set by the first.
- You get a string called
order. It lists letters in the exact order you must follow. - You get a string called
s. You rearrange its letters to matchorder. - A letter in
sthat is not inordercan go anywhere. We place it at the end. - We call this a priority order, because each letterβs place comes from the
orderstring.
For order = "cba" and s = "abcd": c comes first, then b, then a. The letter d is not in order, so it goes last. The answer is "cbad".
Input: order = "cba", s = "abcd"Output: "cbad"
Explanation: c, b, a follow the order string. d is not listed, so it goes last.Here is the rule drawn out. Each letter in s looks up its place in order.
π’ Approach 1: Sort With a Comparator (Brute Force)
Sort the letters of s, but by their place in order instead of A to Z.
The idea:
- Give the sort a comparator. That is the rule the sort uses to decide which letter comes first.
- The rule: a letterβs position in
orderis its rank. - A letter not in
ordergets a large rank, so it lands at the end.
How it works:
- For every pair of letters, look up both ranks in
order. - The smaller rank comes first.
Why it is weak:
- A sort compares letters again and again.
- Every compare does a lookup in
order. - Time grows as O(n log n), where n is the length of
s.
Here is the comparator-style code for that idea:
def custom_sort_string(order, s): rank = {ch: i for i, ch in enumerate(order)} return "".join(sorted(s, key=lambda ch: rank.get(ch, len(order))))β‘ Approach 2: Counting Sort (Best)
The idea in one line: we never compare letters, we just count them and rebuild.
The idea:
- We only need how many times each letter appears in
s. - Then we walk
orderand add each letter that many times. - This is a counting sort. It builds the answer from counts, not compares.
How it works:
- Count every letter in
sinto a small table of 26 slots. - Walk
orderone letter at a time. Add each letter as many times as its count. - Add the leftovers last. Those are letters in
sthat were never inorder.
Why it is fast:
- No comparisons at all. We only read counts.
- One pass to count, one pass to build. So O(n) time.
Here is a dry run of the counting approach on the example.
Steps to Solve
- Count how many times each letter appears in
s. Store the counts in a small table. - Create an empty result.
- Walk through
orderone letter at a time. - For each letter in
order, add it to the result that many times, then set its count to zero. - After
orderis done, walk through the table again and add any letter that still has a count left. - Join everything into the final string and return it.
This Python version uses a Counter, which is a ready-made tool that counts how many times each letter appears.
from collections import Counter
def custom_sort(order, s): count = Counter(s) # number -> count of each letter in s result = [] for ch in order: # follow the custom order result.append(ch * count[ch]) # add ch that many times count[ch] = 0 # mark it as used for ch, c in count.items(): # add leftover letters result.append(ch * c) return "".join(result)
print(custom_sort("cba", "abcd"))The output of the above code will be:
cbadLet us walk through the Python version line by line, because it shows the idea most clearly.
count = Counter(s) builds a table of how many times each letter shows up in s. For "abcd" every letter has a count of one. We start here because counting once lets us skip all the comparing later.
for ch in order: walks through the order string. This is what makes the sort custom. We do not go A to Z. We go in the exact order the problem gave us.
result.append(ch * count[ch]) adds that letter as many times as it appeared. In Python ch * 2 gives "cc". So if a letter appeared twice, we add two copies in one move.
count[ch] = 0 marks the letter as done. This matters. It stops us from adding the same letter again in the leftover step.
for ch, c in count.items(): handles the leftovers. These are letters that were in s but never in order, like d. They still have a count, so we add them now. They land at the end, which is exactly the rule.
return "".join(result) glues all the pieces into one final string. We built a list first and joined at the end because joining once is faster than adding to a string over and over.
β±οΈ Time and Space Complexity
The comparator sort is fine but it compares letters again and again, so it costs O(n log n) time. The counting sort skips all comparisons. It counts once, then reads the counts, so it runs in O(n) time. Both need a small fixed table of 26 counts, so the extra space is tiny. That makes counting the clear winner, since it drops the time to O(n) for almost no extra cost.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Sort with custom comparator | O(n log n) | O(n) |
| Counting sort | O(n) | O(1) for the 26-letter table |
Tip
In an interview, say the comparator-sort idea first. It shows you understand the order rule. Then explain how counting removes the sort completely and gets you to O(n). That jump is what they want to see.
π§© Key Takeaways
- β
You sort by a custom order, not by A to Z. Each letterβs place comes from the
orderstring. - β Counting how many times each letter appears lets you skip all the comparing.
- β
Walk through
orderand add each letter as many times as its count. - β
Letters not in
orderstill appear in the answer. Add them at the end. - β Counting sort runs in O(n) time, faster than the O(n log n) comparator sort.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What decides the order of letters in the answer?
Why: You arrange the letters of s to match the custom order given by the order string.
- 2
What happens to letters in s that are not in the order string?
Why: Letters not listed in order can go anywhere, and the common rule is to put them at the end.
- 3
Why is counting sort faster than the comparator sort here?
Why: Counting sort tallies each letter once and reads the counts, so it skips the O(n log n) comparisons.
- 4
What is the time complexity of the counting sort approach?
Why: Counting each letter and reading the counts both take linear time, so the total is O(n).