DSA Patterns
Cyclic Sort
Master the art of in-place sorting for specific number ranges
Cyclic Sort Pattern
Introduction
Cyclic Sort is a pattern that deals with problems involving arrays containing numbers in a given range. Itβs particularly useful when you have numbers from 1 to N or 0 to N-1. The beauty of this pattern lies in its ability to sort in O(n) time complexity with O(1) space complexity.
Why Learn This Pattern?
-
Efficiency Benefits
- O(n) time complexity
- O(1) space complexity
- In-place sorting
- Minimal number of writes
-
Common Applications
- Finding missing numbers
- Finding duplicate numbers
- Array permutations
- Range-based array problems
- Data integrity verification
Understanding Cyclic Sort
-
Core Principle The main idea is that each number should be at its correct position:
For 1 to N: number i should be at index (i-1) For 0 to N-1: number i should be at index i Example (1 to N): Input: [3, 1, 5, 4, 2] Output: [1, 2, 3, 4, 5] Example (0 to N-1): Input: [2, 0, 4, 1, 3] Output: [0, 1, 2, 3, 4]
-
How It Works
# Visual representation of sorting [3, 1, 5, 4, 2] Step 1: [3, 1, 5, 4, 2] β swap 3 to index 2 [5, 1, 3, 4, 2] Step 2: [5, 1, 3, 4, 2] β swap 5 to index 4 [2, 1, 3, 4, 5] Step 3: [2, 1, 3, 4, 5] β swap 2 to index 1 [1, 2, 3, 4, 5] Result: [1, 2, 3, 4, 5]
Basic Implementation
-
Standard Cyclic Sort For arrays containing numbers from 1 to N:
def cyclicSort(nums): """ Sort array containing numbers 1 to N Time Complexity: O(n) Space Complexity: O(1) """ i = 0 while i < len(nums): correct_pos = nums[i] - 1 # For 1 to N if nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 return nums # Example: # Input: [3, 1, 5, 4, 2] # Output: [1, 2, 3, 4, 5]
-
Zero-Based Cyclic Sort For arrays containing numbers from 0 to N-1:
def cyclicSort(nums): """ Sort array containing numbers 0 to N-1 Time Complexity: O(n) Space Complexity: O(1) """ i = 0 while i < len(nums): correct_pos = nums[i] # For 0 to N-1 if nums[i] < len(nums) and nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 return nums # Example: # Input: [2, 0, 4, 1, 3] # Output: [0, 1, 2, 3, 4]
Detailed Examples with Step-by-Step Solutions
-
Complete Example: Finding Missing Number Problem: Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing.
Input: nums = [3, 0, 1] Target: Find the missing number Step-by-step solution: Initial array: [3, 0, 1] Step 1: i = 0, nums[0] = 3 3 should be at index 3, but that's out of bounds Skip since 3 >= len(nums) [3, 0, 1] i++ Step 2: i = 1, nums[1] = 0 0 should be at index 0, swap with 3 [0, 3, 1] i++ Step 3: i = 2, nums[2] = 1 1 should be at index 1, swap with 3 [0, 1, 3] i++ Final array: [0, 1, 3] Check indices: index 0: nums[0] = 0 β index 1: nums[1] = 1 β index 2: nums[2] = 3 β (should be 2) Therefore, 2 is missing
-
Complete Example: Finding Duplicate Problem: Find the duplicate number in an array of n+1 integers where each integer is in the range [1, n].
Input: nums = [1, 3, 4, 2, 2] Target: Find the duplicate number Step-by-step solution: Initial array: [1, 3, 4, 2, 2] Step 1: i = 0, nums[0] = 1 1 should be at index 0 Already correct, i++ [1, 3, 4, 2, 2] Step 2: i = 1, nums[1] = 3 3 should be at index 2, swap [1, 4, 3, 2, 2] Step 3: i = 1, nums[1] = 4 4 should be at index 3, swap [1, 2, 3, 4, 2] Step 4: i = 1, nums[1] = 2 2 should be at index 1 Already correct, i++ [1, 2, 3, 4, 2] Step 5: i = 2, nums[2] = 3 3 should be at index 2 Already correct, i++ [1, 2, 3, 4, 2] Step 6: i = 3, nums[3] = 4 4 should be at index 3 Already correct, i++ [1, 2, 3, 4, 2] Step 7: i = 4, nums[4] = 2 2 should be at index 1 But nums[1] is already 2 Found duplicate: 2
-
Complete Example: First Missing Positive Problem: Find the smallest missing positive integer in an unsorted array.
Input: nums = [3, 4, -1, 1] Target: Find first missing positive integer Step-by-step solution: Initial array: [3, 4, -1, 1] Step 1: i = 0, nums[0] = 3 3 should be at index 2, swap [β1, 4, 3, 1] Step 2: i = 0, nums[0] = -1 Skip negative number, i++ [β1, 4, 3, 1] Step 3: i = 1, nums[1] = 4 4 should be at index 3, swap [β1, 1, 3, 4] Step 4: i = 1, nums[1] = 1 1 should be at index 0, but skip since nums[0] < 0 i++ [β1, 1, 3, 4] Step 5: i = 2, nums[2] = 3 3 should be at index 2 Already correct, i++ [β1, 1, 3, 4] Step 6: i = 3, nums[3] = 4 4 should be at index 3 Already correct, i++ [β1, 1, 3, 4] Check indices starting from 1: index 0 should have 1: missing index 1 has 1: present index 2 has 3: present index 3 has 4: present Therefore, 2 is the first missing positive integer
-
Complete Example: Find All Missing Numbers Problem: Find all numbers that are missing from an array containing n numbers in range [1, n].
Input: nums = [4, 3, 2, 7, 8, 2, 3, 1] Target: Find all missing numbers Step-by-step solution: Initial array: [4, 3, 2, 7, 8, 2, 3, 1] Step 1: i = 0, nums[0] = 4 4 should be at index 3, swap [7, 3, 2, 4, 8, 2, 3, 1] Step 2: i = 0, nums[0] = 7 7 should be at index 6, swap [3, 3, 2, 4, 8, 2, 7, 1] Continue swapping until no more valid swaps possible... Final array: [1, 2, 3, 4, 3, 2, 7, 8] Check each index: index 0: nums[0] = 1 β index 1: nums[1] = 2 β index 2: nums[2] = 3 β index 3: nums[3] = 4 β index 4: nums[4] = 3 β (should be 5) index 5: nums[5] = 2 β (should be 6) index 6: nums[6] = 7 β index 7: nums[7] = 8 β Therefore, missing numbers are [5, 6]
Common Problem Patterns
-
Find Missing Number Find the missing number in an array containing n distinct numbers in range [0, n].
Key insight: After sorting, the first number thatβs not at its correct index is missing.
def findMissing(nums): """ Time Complexity: O(n) Space Complexity: O(1) """ i = 0 while i < len(nums): correct_pos = nums[i] if nums[i] < len(nums) and nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 # Find first number not in correct position for i in range(len(nums)): if nums[i] != i: return i return len(nums) # Example: # Input: [3, 0, 1] # Output: 2
-
Find All Missing Numbers Find all missing numbers in an array containing numbers from 1 to n.
def findAllMissing(nums): """ Time Complexity: O(n) Space Complexity: O(1) """ i = 0 while i < len(nums): correct_pos = nums[i] - 1 if nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 missing = [] for i in range(len(nums)): if nums[i] != i + 1: missing.append(i + 1) return missing # Example: # Input: [4, 3, 2, 7, 8, 2, 3, 1] # Output: [5, 6]
-
Find Duplicate Number Find the duplicate number in an array containing n+1 numbers from 1 to n.
def findDuplicate(nums): """ Time Complexity: O(n) Space Complexity: O(1) """ i = 0 while i < len(nums): correct_pos = nums[i] - 1 if nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: if i != correct_pos: return nums[i] i += 1 return -1 # Example: # Input: [1, 3, 4, 2, 2] # Output: 2
Advanced Variations
-
Find All Duplicates Find all duplicates in an array where each number appears once or twice.
def findAllDuplicates(nums): duplicates = [] i = 0 while i < len(nums): correct_pos = nums[i] - 1 if nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 for i in range(len(nums)): if nums[i] != i + 1: duplicates.append(nums[i]) return duplicates # Example: # Input: [4, 3, 2, 7, 8, 2, 3, 1] # Output: [2, 3]
-
First Missing Positive Find the smallest missing positive number in an unsorted array.
def firstMissingPositive(nums): i = 0 n = len(nums) # Ignore non-positive and numbers greater than n while i < n: correct_pos = nums[i] - 1 if 0 < nums[i] <= n and nums[i] != nums[correct_pos]: nums[i], nums[correct_pos] = nums[correct_pos], nums[i] else: i += 1 # Find first missing positive number for i in range(n): if nums[i] != i + 1: return i + 1 return n + 1 # Example: # Input: [3, 4, -1, 1] # Output: 2
Edge Cases and Common Pitfalls
-
Input Validation
- Empty array
- Single element array
- Array with all same elements
- Array with negative numbers
- Array with numbers out of range
-
Common Mistakes
- Forgetting to handle zero-based vs one-based indexing
- Not handling duplicates properly
- Incorrect position calculation
- Infinite loops in swap logic
-
Performance Considerations
- Minimize number of swaps
- Handle edge cases efficiently
- Consider input size constraints
Practice Problems
-
Basic
- Sort array with numbers 1 to N
- Find missing number
- Find duplicate number
-
Intermediate
- Find all missing numbers
- Find all duplicates
- First missing positive
-
Advanced
- Find corrupt pair
- Find smallest missing positive
- K missing positive numbers
Key Takeaways
-
When to Use
- Numbers in range 1 to N or 0 to N-1
- Need in-place sorting
- Looking for missing/duplicate elements
- Space complexity is a constraint
-
Advantages
- O(n) time complexity
- O(1) space complexity
- Minimal number of writes
- In-place algorithm
-
Limitations
- Only works with specific number ranges
- Not suitable for general sorting
- May not handle duplicates well
- Requires modifiable array
Remember: The key to solving cyclic sort problems is to:
- Identify the number range
- Use correct position formula
- Handle edge cases properly
- Consider duplicates carefully
- Minimize number of swaps
Articles & Tutorials
Visualizations
Cyclic Sort Visualization
Interactive visualization of cyclic sort algorithm
Interactive Cyclic Sort
Step by step visualization of cyclic sort algorithm
Array Transformation Visualizer
Visual guide to array transformation using cyclic sort
Missing Numbers Visualization
Interactive visualization of finding missing/duplicate numbers
Visualizer not available for this pattern yet. We're working on it!