97 lines
3.2 KiB
YAML
97 lines
3.2 KiB
YAML
name: Cyclic Sort
|
|
slug: cyclic-sort
|
|
difficulty_level: 2
|
|
pattern_type: algorithm
|
|
display_order: 21
|
|
|
|
description: >
|
|
Place each number at its "correct" index when dealing with arrays containing
|
|
numbers in the range [1, n] or [0, n-1].
|
|
|
|
when_to_use: |
|
|
- Array contains numbers from 1 to n (or 0 to n-1)
|
|
- Finding missing/duplicate numbers in such arrays
|
|
- Problems asking for O(1) space and O(n) time
|
|
- "First missing positive" type problems
|
|
|
|
metaphor: |
|
|
Imagine a row of n chairs numbered 1 to n, and n people each holding a
|
|
ticket with their seat number. Instead of searching for each person's seat,
|
|
you ask everyone to swap positions until they're in their ticketed seat.
|
|
After at most n swaps, everyone is seated correctly.
|
|
|
|
core_concept: |
|
|
For an array where values should map directly to indices (e.g., value 3
|
|
belongs at index 2 if 1-indexed), repeatedly swap each element to its
|
|
correct position until the array is "sorted."
|
|
|
|
Key insight: Each swap places at least one element correctly, so at most
|
|
n swaps are needed -> O(n) time with O(1) space.
|
|
|
|
code_template: |
|
|
def cyclic_sort(nums: list[int]) -> list[int]:
|
|
"""Sort array where values are in range [1, n]."""
|
|
i = 0
|
|
while i < len(nums):
|
|
# Correct index for value nums[i] (1-indexed value -> 0-indexed position)
|
|
correct_idx = nums[i] - 1
|
|
|
|
# If not in correct position and not a duplicate, swap
|
|
if nums[i] != nums[correct_idx]:
|
|
nums[i], nums[correct_idx] = nums[correct_idx], nums[i]
|
|
else:
|
|
i += 1
|
|
return nums
|
|
|
|
def find_missing(nums: list[int]) -> int:
|
|
"""Find missing number after cyclic sort."""
|
|
cyclic_sort(nums)
|
|
for i, num in enumerate(nums):
|
|
if num != i + 1:
|
|
return i + 1
|
|
return len(nums) + 1
|
|
|
|
recognition_signals:
|
|
- "array of length n with values 1 to n"
|
|
- "find the missing number"
|
|
- "find the duplicate"
|
|
- "first missing positive"
|
|
- "O(1) extra space"
|
|
- "in-place rearrangement"
|
|
|
|
common_mistakes:
|
|
- title: Infinite Loop on Duplicates
|
|
description: |
|
|
Swapping endlessly when current value equals value at target index
|
|
(both are duplicates).
|
|
fix: |
|
|
Check `nums[i] != nums[correct_idx]` before swapping, not just
|
|
`nums[i] != correct_idx + 1`.
|
|
|
|
- title: Wrong Index Calculation
|
|
description: |
|
|
Confusing 0-indexed vs 1-indexed. If values are 1 to n, correct
|
|
index is `value - 1`. If values are 0 to n-1, correct index equals value.
|
|
fix: |
|
|
Clearly define the mapping: `correct_idx = nums[i] - 1` for 1-indexed values.
|
|
|
|
variations:
|
|
- name: Find Missing Number
|
|
description: After cyclic sort, scan for index where value != index + 1
|
|
example: "missing-number"
|
|
- name: Find Duplicate
|
|
description: After cyclic sort, find where value != expected
|
|
example: "find-the-duplicate-number"
|
|
- name: First Missing Positive
|
|
description: Ignore negatives and values > n, then cyclic sort
|
|
example: "first-missing-positive"
|
|
- name: Find All Missing Numbers
|
|
description: Collect all indices where value != expected
|
|
example: "find-all-numbers-disappeared-in-an-array"
|
|
|
|
related_patterns:
|
|
- counting-sort
|
|
- fast-slow-pointers
|
|
|
|
prerequisite_patterns: []
|