F1 Backtracking template: choose-explore-unchoose

Every backtracking problem follows choose → explore → unchoose. The only things that change are the state, choices, and goal condition.

BACKTRACKING TEMPLATE
─────────────────────
def backtrack(state, choices):
    if is_goal(state):
        result.append(state[:])  # copy!
        return

    for choice in choices:
        if not is_valid(choice, state):
            continue

        # 1. CHOOSE
        state.append(choice)      # or modify state

        # 2. EXPLORE
        backtrack(state, next_choices)

        # 3. UNCHOOSE (undo mutation)
        state.pop()               # or restore state

CRITICAL POINTS:
  □ Copy state on goal (state[:] or list(state))
  □ Always undo mutations (symmetric choose/unchoose)
  □ Prune early with is_valid before recursing
  □ Track 'start index' for combinations to avoid dupes
F2 Backtracking vs DP: when to use which

DP counts/optimizes. Backtracking enumerates. If you need all solutions, backtracking. If you need the best/count, DP.

BACKTRACKING vs DP — DECISION GUIDE
────────────────────────────────────
USE BACKTRACKING when:
  □ Need ALL solutions (not just count/optimal)
  □ Solution is a sequence of choices (permutation, path)
  □ Constraints are complex (placement rules, validity)
  □ Search space can be pruned effectively
  Examples: N-Queens, Sudoku, all permutations

USE DP when:
  □ Need COUNT or OPTIMAL VALUE (not all solutions)
  □ Overlapping subproblems exist
  □ Optimal substructure holds
  □ State space is polynomial
  Examples: coin change, LCS, knapsack

BOTH work but pick wisely:
  "Number of ways to..." → usually DP (count)
  "Find all ways to..."  → usually backtracking (enumerate)
  "Min cost to..."       → usually DP (optimize)

HYBRID: precompute with DP, enumerate with backtracking
  Example: palindrome partitioning (DP palindrome check
           + backtracking to list all partitions)
F3 Permutation vs combination vs subset: decision tree

Three core enumeration patterns. The only differences: does order matter, how many to pick, and the start index.

PERMUTATION vs COMBINATION vs SUBSET
─────────────────────────────────────
         ORDER     PICK ALL?   START IDX?
PERM     matters   yes (n)     no (use visited[])
COMBO    no        k items     yes (avoid revisit)
SUBSET   no        any count   yes (avoid revisit)

TEMPLATES:
  Permutations: for i in range(n):
                  if not used[i]: choose i
  Combinations: for i in range(start, n):
                  choose i, recurse with start=i+1
  Subsets:      for i in range(start, n):
                  choose i, record at every node

DUPLICATE HANDLING (sorted input):
  if i > start and nums[i] == nums[i-1]: continue

REUSE ALLOWED (combination sum):
  recurse with start=i instead of start=i+1

QUICK CHECK:
  "order matters?" → permutation → O(n!)
  "fixed size k?"  → combination → O(C(n,k))
  "all sizes?"     → subset → O(2^n)