String Reorder
Problem Overview
| Attribute | Value |
|---|---|
| Difficulty | Easy |
| Category | Strings / Sorting |
| Time Limit | 1 second |
| Key Technique | Character Frequency Counting / Sorting |
| CSES Link | String Reorder |
Learning Goals
After solving this problem, you will be able to:
- Understand lexicographic ordering of characters
- Use character frequency counting for efficient string manipulation
- Build strings from character frequencies in sorted order
- Choose between sorting-based and counting-based approaches
Problem Statement
Problem: Given a string, reorder its characters to create the lexicographically smallest possible string.
Input: A string s consisting of lowercase letters
Output: The lexicographically smallest string using all characters
Constraints:
-
1 <= s <= 10^6 - String contains only lowercase letters a-z
Example
Input: dcba
Output: abcd
Input: monkey
Output: ekmnoy
Explanation: Sorting characters gives the lexicographically smallest arrangement.
Intuition: How to Think About This Problem
Key Question: What arrangement of characters produces the smallest string lexicographically?
The lexicographically smallest string places the smallest characters first. Since ‘a’ < ‘b’ < … < ‘z’, we simply need all characters in ascending order.
Analogy: Think of organizing books alphabetically - ‘d’, ‘c’, ‘b’, ‘a’ becomes ‘a’, ‘b’, ‘c’, ‘d’.
Solution 1: Sorting Approach
Idea
Simply sort all characters in the string and concatenate them.
Code
Python:
def solve_sorting(s):
"""
Time: O(n log n) - sorting dominates
Space: O(n) - storing sorted characters
"""
return ''.join(sorted(s))
def main():
s = input().strip()
print(solve_sorting(s))
if __name__ == "__main__":
main()
Complexity
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n log n) | Standard comparison sort |
| Space | O(n) | Storage for sorted result |
Solution 2: Optimal - Counting Sort
Key Insight
The Trick: Since we only have 26 possible characters (a-z), we can count frequencies and rebuild the string in O(n) time.
Algorithm
- Count frequency of each character (array of size 26)
- Iterate through characters ‘a’ to ‘z’
- For each character, append it frequency[char] times to result
Dry Run Example
Input: s = "dcba"
Step 1: Count frequencies
'd' -> freq[3] = 1
'c' -> freq[2] = 1
'b' -> freq[1] = 1
'a' -> freq[0] = 1
freq = [1, 1, 1, 1, 0, 0, ..., 0]
^a ^b ^c ^d
Step 2: Build result
i=0: append 'a' x 1 -> "a"
i=1: append 'b' x 1 -> "ab"
i=2: append 'c' x 1 -> "abc"
i=3: append 'd' x 1 -> "abcd"
Result: "abcd"
Code
Python:
def solve_counting(s):
"""
Counting sort: O(n) time, O(1) space.
"""
freq = [0] * 26
for c in s:
freq[ord(c) - ord('a')] += 1
result = []
for i in range(26):
if freq[i] > 0:
result.append(chr(ord('a') + i) * freq[i])
return ''.join(result)
def main():
s = input().strip()
print(solve_counting(s))
if __name__ == "__main__":
main()
Complexity
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n) | Single pass to count, single pass to build |
| Space | O(1) | Fixed 26-element array |
Common Mistakes
Mistake 1: Inefficient String Concatenation (Python)
# WRONG - O(n^2) due to string immutability
result = ""
for i in range(26):
for j in range(freq[i]):
result += chr(ord('a') + i)
# CORRECT - O(n) using list and join
result = []
for i in range(26):
if freq[i] > 0:
result.append(chr(ord('a') + i) * freq[i])
return ''.join(result)
Mistake 2: Off-by-One in Character Index
# WRONG - uses raw ASCII value (97 for 'a')
freq[ord(c)]
# CORRECT - normalize to 0-25 range
freq[ord(c) - ord('a')]
Edge Cases
| Case | Input | Output | Why |
|---|---|---|---|
| Single character | a |
a |
Already sorted |
| Already sorted | abc |
abc |
No change needed |
| Reverse sorted | zyx |
xyz |
Complete reversal |
| All same | aaaa |
aaaa |
No reordering needed |
| With repeats | zzzzaaaabbbb |
aaaabbbbzzzz |
Group same characters |
When to Use This Pattern
Use Counting Sort When:
- Input has a small, fixed alphabet (like lowercase letters)
- You need O(n) time complexity
- Characters can be mapped to array indices
Use Standard Sorting When:
- Input alphabet is large or unknown
- Implementation simplicity is preferred
Pattern Recognition Checklist:
- Need to reorder characters? -> Consider sorting or counting
- Fixed small alphabet? -> Counting sort is optimal
- Need lexicographically smallest/largest? -> Sort ascending/descending
Related Problems
Easier
| Problem | Why It Helps |
|---|---|
| Repetitions (CSES) | Basic character iteration |
Similar Difficulty
| Problem | Key Difference |
|---|---|
| Palindrome Reorder (CSES) | Arrange into palindrome |
| Sort Characters By Frequency (LeetCode) | Sort by frequency, not alphabetically |
Harder
| Problem | New Concept |
|---|---|
| Creating Strings (CSES) | Generate all permutations |
| Reorganize String (LeetCode) | No two adjacent characters same |
Key Takeaways
- Core Idea: Sorting characters produces lexicographically smallest arrangement
- Time Optimization: Counting sort achieves O(n) for fixed alphabets
- Space Trade-off: O(26) = O(1) fixed space vs O(n) for general sorting
- Pattern: Counting sort is powerful when alphabet size is bounded
Practice Checklist
Before moving on, make sure you can:
- Solve this problem without looking at the solution
- Explain the difference between O(n log n) and O(n) solutions
- Implement counting sort from memory
- Identify when counting sort is applicable
Additional Resources
- CP-Algorithms: Counting Sort
- CSES Creating Strings I - String permutations