Skip to content
mlmentorship

Subsets

Return every subset of the input values.

Published · 4 min read ·Core ·Intermediate

30-second answer map

Visual first · depth when needed

Save every current path, then recurse only to larger indices and pop the chosen value on return.

Preparing the visual…

ML breadth · active recall

Practice before you read

8 minutes. Explain the mechanism, why it works, when it fails, and one alternative.

How practice works

ML breadth · closed-book attempt

Subsets

Explain the mechanism, why it works, when it fails, and one alternative.

08:00recommended time

Closing or reloading clears the scratchpad. Only score, weak rubric dimensions, attempt count, and retry date can be stored locally.

Return every subset of the input values.

Start with the concrete trace below. It shows the state the algorithm must carry as it runs.

Problem trace

Subsets: Save every current path, then recurse only to larger indices and pop the chosen value on return.

Input and goalReturn every subset of the input values.
Save the empty pathchoose(0) first copies [] into answer; indices 0, 1, and 2 remain available.
[]active callstart 0
inputnums = [1, 2, 3]columnspath | startactionsave []answer[[]]

Recognize it
Use this pattern when every combination of distinct input positions is valid and order does not matter, so each partial selection must be emitted once.
Keep true
On entry to choose(start), path contains indices in strictly increasing order, answer already contains every path visited earlier in DFS order, and only indices start or greater may extend this path.
Reuse it
When order should not create duplicates, advance a start boundary after each choice; this same skeleton generates combinations, k-subsets, and increasing-index selections.
Read it this way: choose(0) first copies [] into answer; indices 0, 1, and 2 remain available. Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.

Pattern: Backtracking with a start position.

Simple idea: Every partial path is already one valid subset. Save it. Then add each value that comes after the last chosen position.

def subsets(nums: list[int]) -> list[list[int]]:
   answer: list[list[int]] = []
   path: list[int] = []

   def choose(start: int) -> None:
      answer.append(path.copy())
      for index in range(start, len(nums)):
         path.append(nums[index])
         choose(index + 1)
         path.pop()

   choose(0)
   return answer

Cost: time and working space, not counting the answer.