function cyclicSort(nums) { let i = 0; while (i < nums.length) { const correctIndex = nums[i] - 1; // For range [1,n] if (nums[i] !== nums[correctIndex]) { // Swap to place element at correct position [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; // Element already at correct position } } return nums;}// [3, 1, 5, 4, 2] -> [1, 2, 3, 4, 5]// Time: O(n), Space: O(1)// Key insight: Each element swapped at most once
Example: Cyclic sort for range [0, n-1]
function cyclicSortZeroBased(nums) { let i = 0; while (i < nums.length) { const correctIndex = nums[i]; // For range [0,n-1] if (nums[i] < nums.length && nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } return nums;}// [2, 0, 3, 1] -> [0, 1, 2, 3]
2. Find Missing Numbers O(n) Time
Problem Variant
Approach
Complexity
Key Insight
Single Missing
Cyclic sort then find index where arr[i] ≠ i+1
O(n), O(1)
First incorrect position has missing number
All Missing
Cyclic sort then collect all incorrect positions
O(n), O(k)
k missing numbers at wrong indices
Missing in Range
Place elements, scan for gaps
O(n), O(1)
Expected value vs actual value mismatch
Without Modification
XOR or sum formula approach
O(n), O(1)
Alternative when can't modify array
Example: Find missing number (single)
function findMissingNumber(nums) { let i = 0; const n = nums.length; // Cyclic sort for range [0, n] while (i < n) { const correctIndex = nums[i]; if (nums[i] < n && nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } // Find missing number for (let i = 0; i < n; i++) { if (nums[i] !== i) { return i; // Missing number } } return n; // Missing number is n}// [3, 0, 1] -> 2// [0, 1] -> 2// [9,6,4,2,3,5,7,0,1] -> 8
Example: Find all missing numbers
function findDisappearedNumbers(nums) { let i = 0; // Cyclic sort for range [1, n] while (i < nums.length) { const correctIndex = nums[i] - 1; if (nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } // Find all missing numbers const missing = []; for (let i = 0; i < nums.length; i++) { if (nums[i] !== i + 1) { missing.push(i + 1); } } return missing;}// [4,3,2,7,8,2,3,1] -> [5,6]// After sort: [1,2,3,2,3,8,7,8], positions 4,5 have wrong values
3. Find Duplicates O(1) Space Complexity
Detection Method
Strategy
Works For
Trade-off
Cyclic Sort Scan
After sorting, duplicate at wrong position
Range [1,n] with one duplicate
Modifies array
Swap Detection
During swap, if both same value = duplicate
Find during sort process
Early termination possible
Index Marking
Use sign to mark visited indices
Positive integers only
Reversible modification
Multiple Duplicates
Collect all positions with wrong values
Multiple duplicates present
Returns all duplicates
Example: Find duplicate number
function findDuplicate(nums) { let i = 0; while (i < nums.length) { const correctIndex = nums[i] - 1; if (nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } // Find duplicate for (let i = 0; i < nums.length; i++) { if (nums[i] !== i + 1) { return nums[i]; } } return -1;}// [1,3,4,2,2] -> 2
Example: Find all duplicates
function findDuplicates(nums) { let i = 0; while (i < nums.length) { const correctIndex = nums[i] - 1; if (nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } const duplicates = []; for (let i = 0; i < nums.length; i++) { if (nums[i] !== i + 1) { duplicates.push(nums[i]); } } return duplicates;}
Example: Find duplicates without modification (index marking)
function findDuplicatesIndexMarking(nums) { const duplicates = []; for (let i = 0; i < nums.length; i++) { const index = Math.abs(nums[i]) - 1; if (nums[index] < 0) { // Already negative - duplicate found duplicates.push(Math.abs(nums[i])); } else { // Mark as visited by negating nums[index] = -nums[index]; } } // Restore array (optional) for (let i = 0; i < nums.length; i++) { nums[i] = Math.abs(nums[i]); } return duplicates;}// [4,3,2,7,8,2,3,1] -> [2,3]
4. Corrupt Pairs Detection Pattern
Problem Type
Definition
Detection
Solution
Set Mismatch
One number duplicated, one missing
Find both using cyclic sort
[duplicate, missing]
Corrupt Pair
Two numbers swapped incorrectly
Both positions have wrong values
Return the swapped pair
XOR Technique
Use XOR to find different elements
XOR all elements with expected range
Result is duplicate XOR missing
Sum Difference
Compare actual sum vs expected sum
Difference reveals relationship
Combined with product or sum of squares
Example: Find corrupt pair (set mismatch)
function findErrorNums(nums) { let i = 0; // Cyclic sort while (i < nums.length) { const correctIndex = nums[i] - 1; if (nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } // Find duplicate and missing for (let i = 0; i < nums.length; i++) { if (nums[i] !== i + 1) { return [nums[i], i + 1]; // [duplicate, missing] } } return [-1, -1];}// [1,2,2,4] -> [2,3] (2 is duplicate, 3 is missing)// [1,1] -> [1,2]
5. First Missing Positive Integer Problem
Challenge
Solution
Key Insight
Complexity
Range Constraint
Only care about positives in [1, n]
Answer must be in [1, n+1]
Ignore negatives and > n
Cyclic Sort Modified
Sort only valid range values
Skip out-of-range during swap
O(n), O(1)
First Gap
First index where arr[i] ≠ i+1
Missing positive at that index
Return index + 1
All Present Case
If [1..n] all present, answer is n+1
Perfect sequence means next is missing
Edge case handling
Example: First missing positive integer
function firstMissingPositive(nums) { let i = 0; const n = nums.length; // Cyclic sort - only for valid range [1, n] while (i < n) { const correctIndex = nums[i] - 1; // Only swap if value in valid range and not at correct position if (nums[i] > 0 && nums[i] <= n && nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } // Find first missing positive for (let i = 0; i < n; i++) { if (nums[i] !== i + 1) { return i + 1; } } // All [1..n] present, answer is n+1 return n + 1;}// [1,2,0] -> 3// [3,4,-1,1] -> 2// [7,8,9,11,12] -> 1
Note: This is one of the hardest cyclic sort problems. The key is recognizing that the first missing positive must be in range [1, n+1], so we only need to consider elements in [1, n] during sorting.
6. Range Validation Techniques
Validation Type
Check
Purpose
Example
Bounds Check
0 <= val < n or 1 <= val <= n
Prevent out-of-bounds access
Avoid array index errors
Duplicate Position
nums[i] === nums[correctIndex]
Detect when element already correct
Avoid infinite swap loops
Self-loop Prevention
i !== correctIndex
Don't swap element with itself
Optimization, not required
Valid Value Range
Filter out negatives, zeros, or too large
Skip irrelevant values
First missing positive problem
Example: Safe cyclic sort with validation
function safeCyclicSort(nums) { let i = 0; while (i < nums.length) { const val = nums[i]; const correctIndex = val - 1; // Comprehensive validation if (val >= 1 && // Lower bound val <= nums.length && // Upper bound val !== nums[correctIndex]) { // Not duplicate [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } return nums;}
Example: Validation for edge cases
function validateAndSort(nums) { // Handle edge cases if (!nums || nums.length === 0) { return []; } if (nums.length === 1) { return nums; } let i = 0; while (i < nums.length) { const correctIndex = nums[i] - 1; if (correctIndex >= 0 && correctIndex < nums.length && nums[i] !== nums[correctIndex]) { [nums[i], nums[correctIndex]] = [nums[correctIndex], nums[i]]; } else { i++; } } return nums;}
Cyclic Sort Pattern Summary
When to Use: Array contains numbers in range [1,n] or [0,n-1]
Core Pattern: Swap elements until each is at correct index position
Time Complexity: O(n) - each element moved at most once
Key Validation: Check bounds and prevent duplicate swaps
Note: Cyclic sort achieves O(n) time with O(1) space by leveraging the property that array indices can store values. The pattern works because each swap places at least one element in its correct position, guaranteeing linear time.
Warning: Always validate before swapping: check nums[i] !== nums[correctIndex] to prevent infinite loops when duplicate exists. Ensure correctIndex is within bounds [0, n-1] to avoid out-of-bounds access. For first missing positive, skip values outside [1, n] range.