PrepStack · Markdown HTML

Subset / combination backtracking

Backtracking and constraint search · HTML

Formal shape

dfs(start,path) chooses a next index i in [start,n). Single-use combinations recurse to i+1; reusable candidates recurse to i. Emit a snapshot when target depth or condition is met.

Recognition signals

False friends

SignalWhy it is different
Only a count or feasibility bitDP or a combinatorial formula can avoid output-level search when the target dimension is manageable.
Different orders are distinct answersThat is permutation or ordered construction; start would erase valid outcomes.
Unconstrained full subset iterationBitmask enumeration may be simpler when no structured pruning is needed.

Core invariant

On entering dfs(start), path indices are strictly increasing and already fixed below start. The call generates exactly completions whose next index is at least start, preventing duplicate orders.

State, transition, and processing order

ItemDefinition
StateNext candidate index start, current path, remaining slots/target, and incrementally maintained constraints such as sum.
TransitionChoose i, update path and constraints, recurse to i+1 or i, then undo exactly that choice.
Frontier / orderThe current path in an implicit decision tree; the loop explores next choices horizontally and recursion deepens vertically.

Python skeleton

def combinations(nums, k):
    out, path = [], []
    def dfs(start):
        if len(path) == k:
            out.append(path.copy())
            return
        need = k - len(path)
        last_start = len(nums) - need
        for i in range(start, last_start + 1):
            path.append(nums[i])
            dfs(i + 1)
            path.pop()
    dfs(0)
    return out

Correctness sketch

  1. Every emitted path has increasing indices, so each index is used at most once in canonical order.
  2. Every k-set has one increasing index sequence, and the loops can follow that sequence to a base case, proving completeness.
  3. Because the canonical sequence is unique, two recursion paths cannot emit the same indexed combination.

Complexity

TimeSpaceParameters
Θ(C(n,k)·k) for k-combinations; Θ(n·2^n) for materialized subsetsO(k) stack/path excluding outputn is candidates and k selections; output size is an unavoidable lower bound.

Edge cases

Error patterns

PatternWhy it fails / fix
Restarting each recursion at zeroThe same set appears in many orders and an index may be reused.
Appending path without a copyEvery result aliases one mutable list and changes together.
Forgetting to pop after recursionSibling branches inherit stale state; choose and undo must be mirror operations.
Assuming start removes duplicate valuesIt removes index-order duplicates, not equal values at distinct indices; sort and skip same-level duplicates.

Selection and exclusion rules

RelationTemplateBoundary

Original micro-example

PartDetail
ResultBlue-red never reappears because its index order is noncanonical.
SetupChoose two colors from [red, blue, green].
TraceIncreasing indices generate red-blue, red-green, and blue-green.

Recall prompts

My notes