Subsets — Include or Exclude Each Element

At each element, make two choices: include it in the current subset or skip it. Collect the current path at every node of the recursion tree — no leaf-only collection needed.

⊂ 2ⁿ Subsets 🔄 With Duplicates (Subsets II) 📋 Collect Every State Time O(2ⁿ·n) Space O(n)
📋 When to Use
  • Generate all 2ⁿ subsets of an array
  • Subsets II: sort input first, skip nums[i]==nums[i-1] when i > start to avoid duplicate subsets
  • Start index increments each recursion — no element reused from earlier positions
  • Collect new ArrayList<>(curr) at the start of each call (includes the empty set automatically)
💡 Unlike permutations, subsets pass i+1 (not 0) to avoid re-picking earlier elements. The empty set [] is added on the very first call before the loop runs.
⚡ Complexity
Time
O(2ⁿ·n)
Space (stack)
O(n)

2ⁿ subsets total; each copy is O(n).
Recursion depth = n (one element per level).
Output space: O(2ⁿ × n) to store all subsets.
n=3 → 8 subsets: [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3].

Live Animation · Subsets / Power Set · LC #78
Problem Given nums = [1,2,3], generate all possible subsets (the power set). At each element decide include or skip — with n=3 elements there are 2³ = 8 subsets total. Collect the current path at every node of the recursion tree, not just at leaves.
Input: nums = [1,2,3] · Answer: 8 subsets: [], [1], [1,2], [1,2,3], [1,3], [2], [2,3], [3]
Step 0 / 15
🔍 Init 📋 Add to Result ➕ Choose Element ↩ Backtrack ✅ Done
Starting the Subsets backtracking with input [1, 2, 3]. We'll collect subsets at every call, building the power set.
// backtrack(start=0, curr=[])
Recursion Tree — nums = [1, 2, 3]
bt(0,[ ]) bt(1,[1]) bt(2,[2]) bt(3,[3]) bt(2,[1,2]) bt(3,[1,3]) bt(3,[2,3]) bt(3,[1,2,3])
Active
In Stack
Returned
Not Visited
📚 Call Stack
— empty —
Input
1
2
3
nums[0..2]
curr[ ]
[ ] empty
Result (subsets found)
none yet
Pattern Skeleton Java 8
// ─── Subsets (all 2ⁿ subsets) ──────────────────────────────────── List<List<Integer>> result = new ArrayList<>(); int[] nums; void backtrack(int start, List<Integer> curr) { result.add(new ArrayList<>(curr)); // collect every state for (int i = start; i < nums.length; i++) { curr.add(nums[i]); // choose backtrack(i + 1, curr); // explore (i+1: no reuse) curr.remove(curr.size() - 1); // un-choose (backtrack) } } // Call: backtrack(0, new ArrayList<>()) // ─── Subsets II (with duplicates — sort first) ─────────────────── void backtrack(int start, List<Integer> curr) { result.add(new ArrayList<>(curr)); for (int i = start; i < nums.length; i++) { if (i > start && nums[i] == nums[i-1]) continue; // skip dup curr.add(nums[i]); backtrack(i + 1, curr); curr.remove(curr.size() - 1); } }
Practice Problems