Subsets (include / exclude)
At each index choose to take it or not; the leaf is one subset.
The partial choice list describes a unique prefix decision path.
01The intuition
Start with what you would do by hand
List every possible team you can pick from three friends, 1, 2 and 3, including the empty team and the full team. By hand you might write: nobody, 1, 2, 3, 12, 13, 23, 123. Eight teams. You probably got there by some mix of memory and checking you had not missed one, and with four friends you would start to lose track. With twenty friends there are over a million teams, and "did I miss one?" is hopeless.
There is a cleaner way to count first. For each friend you make one decision, in or out, and the decisions are independent:
2 × 2 × 2 = 23 = 8 teams, and 2n in general
The pattern turns that counting argument into a procedure that writes each team exactly once.
Build the structure, one piece at a time
Piece one: an index i that walks through the friends in order, 0, 1, 2. At each index you make the one decision for that friend.
Piece two: a path, which is the team built so far. It behaves like a stack: deciding "in" pushes the friend, and undoing that decision pops them.
Piece three: the rule, as a function solve(i): if i is past the last friend, record a copy of the path; otherwise push friend i, call solve(i + 1), pop friend i, and call solve(i + 1) again. "Take, recurse, untake, recurse."
| call | path | what happens |
|---|---|---|
| solve(0) | [] | take 1 |
| solve(1) | [1] | take 2 |
| solve(2) | [1, 2] | take 3 |
| solve(3) | [1, 2, 3] | record 123 |
| back in solve(2) | [1, 2] | pop 3, skip it |
| solve(3) | [1, 2] | record 12 |
| back in solve(1) | [1] | pop 2, skip it, take 3 |
| solve(3) | [1, 3] | record 13, then 1, then 23, 2, 3, and finally the empty team |
The order the teams come out is a depth-first walk of a decision tree with 2 branches at every level and 2n leaves.
Why it is correct
The invariant: when solve(i) is called, the path holds exactly the friends among 0 .. i − 1 who were decided "in". It is true at the start (empty path, i = 0) and each call keeps it: pushing friend i then calling solve(i + 1) hands over a path that is correct for the "in" choice; popping restores the previous path before the "out" choice. Each sequence of decisions is tried exactly once, so each team is recorded exactly once, and every team corresponds to some sequence, so none is missed.
Why it is fast
There are 2n leaves and each costs up to n to copy the path, so the work is
about n · 2n
You cannot beat 2n, because that is how many teams must be written down. The pattern spends nothing beyond the output itself.
How to recognise it in an interview
Cues: "all subsets", "all combinations", "every way to choose", "power set", or a question where n is small (up to about 20) and each item is either used or not. The first thing to say: "each element is in or out, so I will backtrack with take-then-skip and copy the path at the leaves." Subsets is the example above. Subsets II has duplicates; sort first, and when skipping an element also skip its equal neighbours, so each distinct team is still made once. Partition Equal Subset Sum is the same in-or-out tree with a running sum, where pruning or a DP table replaces listing.
02The idea in one line
At each index choose to take it or not; the leaf is one subset.
Reach for it when: Subsets, subsets with duplicates, bitmask enumeration.
Cost: O(2^n) time.
03The walk-through, step by step
The video works one example: Subsets of [1,2,3]. These are its captions in order, so you can follow without the video or check a step you missed.
- At each index: take it or skip it; every leaf is one subset
- Index 0: take 1, push it on the path
- Index 1: take 2, push it on the path
- Index 2: take 3, push it on the path
- Index 3 is past the end: record 123
- Back at index 2: skip 3, pop it off
- Index 3 is past the end: record 12
- Back at index 1: skip 2, pop it off
- Index 2: take 3, push it on the path
- Index 3 is past the end: record 13
- Back at index 2: skip 3, pop it off
- Index 3 is past the end: record 1
- Back at index 0: skip 1, pop it off
- Index 1: take 2, push it on the path
- Index 2: take 3, push it on the path
- Index 3 is past the end: record 23
- Back at index 2: skip 3, pop it off
- Index 3 is past the end: record 2
- Back at index 1: skip 2, pop it off
- Index 2: take 3, push it on the path
- Index 3 is past the end: record 3
- Back at index 2: skip 3, pop it off
- Index 3 is past the end: record ∅
- 8 = 2³ subsets, each index decided twice down every branch
- Exponential by nature: O(2^n · n)
04Asked at Google
6 Google-tagged LeetCode problems use this pattern. Frequency is LeetCode's Google-tag score (higher means reported more often); "last 6 months" marks problems reported in the most recent window of the export.
| Problem | Difficulty | Frequency | Reported |
|---|---|---|---|
| Subsets | Medium | 52 | last 6 months |
| Partition Equal Subset Sum | Medium | 46 | last 6 months |
| Subsets II | Medium | 44 | last 6 months |
| Beautiful Arrangement | Medium | 21 | last 6 months |
| Letter Case Permutation | Medium | 13 | last 6 months |
| Find Minimum Time to Finish All Jobs | Hard | 8 |
05Related patterns
Other patterns in Backtracking: Permutations with a used set, Combination sum with a start index, Grid DFS with undo, Constraint placement with pruning, Generate valid sequences.