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
