feat(patterns): pattern taxonomy + is_optimal

This commit is contained in:
2025-09-08 16:03:14 +01:00
parent 06d99a7f04
commit fe59de3392
28 changed files with 1434 additions and 26 deletions

View File

@@ -0,0 +1,97 @@
name: Divide and Conquer
slug: divide-and-conquer
difficulty_level: 3
pattern_type: algorithm
display_order: 23
description: >
Break a problem into smaller subproblems, solve them independently,
and combine results. Unlike DP, subproblems don't overlap.
when_to_use: |
- Problems naturally split into independent halves
- Merge sort style combining
- Finding kth element efficiently
- Tree-structured recursion without memoization needs
metaphor: |
Imagine sorting a deck of cards by splitting it in half, having two
friends each sort their half, then merging the sorted halves. Each
friend can recursively split their half too. The key: halves are
independent and combining sorted halves is easy.
core_concept: |
Three steps:
1. **Divide:** Split problem into smaller subproblems
2. **Conquer:** Solve subproblems recursively (base case when trivial)
3. **Combine:** Merge subproblem solutions into final answer
Time complexity often follows: T(n) = aT(n/b) + O(n^c)
Solved by Master Theorem.
code_template: |
def merge_sort(arr: list[int]) -> list[int]:
"""Classic divide and conquer example."""
if len(arr) <= 1:
return arr
# Divide
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
# Combine (merge)
return merge(left, right)
def merge(left: list[int], right: list[int]) -> list[int]:
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
recognition_signals:
- "merge sort"
- "find kth largest/smallest"
- "count inversions"
- "closest pair of points"
- "problems on sorted arrays that can be split"
common_mistakes:
- title: Confusing with Dynamic Programming
description: |
D&C subproblems are independent. DP subproblems overlap and need
memoization. Using D&C on overlapping subproblems causes exponential time.
fix: |
Check: Do subproblems share computation? If yes, use DP. If no, use D&C.
- title: Inefficient Combine Step
description: |
If combining takes O(n^2), overall might not be better than brute force.
fix: |
Design O(n) or O(n log n) combine step. Merge sort's merge is O(n).
variations:
- name: Merge Sort
description: Sort by splitting, sorting halves, merging
example: "sort-an-array"
- name: Quick Select
description: Find kth element by partitioning
example: "kth-largest-element-in-an-array"
- name: Count Inversions
description: Count pairs where larger element precedes smaller
example: "count-of-smaller-numbers-after-self"
related_patterns:
- binary-search
- dynamic-programming
prerequisite_patterns:
- binary-search