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