feat(patterns): pattern taxonomy + is_optimal
This commit is contained in:
96
backend/data/patterns/cyclic-sort.yaml
Normal file
96
backend/data/patterns/cyclic-sort.yaml
Normal file
@@ -0,0 +1,96 @@
|
||||
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: []
|
||||
Reference in New Issue
Block a user