Browse curriculum

Solution Space Trees

See the whole search space as a tree: one decision per level, and 2^n leaves that are the answers.

Medium
10 min
Solve on LeetCode

Examples

Input:nums = [1,2,3]
Output:[[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]]
Explain:

The eight leaves, read left to right: taking a number goes left, leaving it goes right.

Input:nums = [0]
Output:[[0],[]]
Explain:

One decision, two leaves. Any order is accepted.

What is a Solution Space Tree?

A solution space tree is the whole set of candidates a problem admits, drawn as a tree. Backtracking never builds it — it walks it, depth first, one branch at a time.

Taking subsets of [1, 2, 3] as the example, and asking one question per level — do I take this number? — gives:

  • Root: nothing decided yet, the candidate is [].
  • Level i: the decision about nums[i], so the tree is exactly as deep as the input is long.
  • A node: a partial candidate — some numbers decided, the rest still open.
  • A leaf: every number decided, so the candidate is complete. There are 2ⁿ of them, and they are the answer.

Why Visualize as a Tree?

Backtracking is fundamentally a Depth-First Search (DFS) on this implicit tree. By visualizing it this way, abstract recursive calls become concrete moves:

  1. Recursive Call: Moving DOWN an edge to a child node.
  2. Base Case: Reaching a Leaf node.
  3. Return Statement (Backtrack): Moving UP to the parent node to try a different branch.

Interactive Visualization

The same subsets as the introduction lesson, and the same LeetCode problem — but one decision per level, so the shape of the search is the thing on screen. A left branch takes the number at that depth (+2), a right branch leaves it (−2), and the line under a node is the candidate so far. Only the leaves are recorded, which is why the count beside the figure climbs to 2ⁿ and no further.

Pruning (The Power of Backtracking)

Subsets has nothing to prune — every leaf is a valid answer, which is exactly why it is the clearest picture of a solution space.

Pruning is what the later lessons add. When a problem has a constraint, a node can be rejected before its children are ever created:

  • Combination Sum: once the running total passes the target, no deeper choice can bring it back.
  • N-Queens: once two queens share a diagonal, nothing below that node is valid.

The saving is the whole subtree, not one node — which is why backtracking beats generating every candidate and filtering afterwards, even though both explore the same space in the worst case.

The Solution: One Decision per Level

The same problem as the introduction lesson, written as one decision per level (LeetCode 78).

Solution Space Trees Code
1var subsets = function(nums) {
2 const result = [];
3 const path = [];
4
5 const backtrack = (i) => {
6 if (i === nums.length) {
7 result.push([...path]);
8 return;
9 }
10 path.push(nums[i]);
11 backtrack(i + 1);
12 path.pop();
13 backtrack(i + 1);
14 };
15
16 backtrack(0);
17 return result;
18};

The approach, step by step

  1. Decide one item per level

    At depth i, either take nums[i] or leave it, and recurse on depth i + 1 for both answers.

  2. Record at the leaves

    When the depth reaches the length of the input every number has been decided, so the candidate is complete — record it and return.

  3. Undo between branches

    Pop the taken number back off before walking the "leave it" branch, so both branches start from the same candidate.

Frequently asked questions

What is a solution space tree?

The set of all candidates a problem admits, drawn as a tree: the root decides nothing, each level fixes one more part of the candidate, and each leaf is a complete candidate. Backtracking is a depth-first walk of that tree, built as it goes rather than stored.


Why does this lesson use the same problem as the introduction?

Because the interesting difference is the shape, not the problem. Enumerating subsets with a start index records an answer at every node; deciding each number in turn records one at every leaf. Same 8 subsets for 3 numbers, two different trees.


Where does pruning fit in?

Pruning rejects a node before its children are created, which removes a whole subtree from the walk. Subsets has nothing to prune because every branch is valid — problems with constraints, like Combination Sum passing its target, are where it pays.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description