DSAPrep
MediumBacktracking

Subsets

Given an integer array nums of unique elements, return all possible subsets (the power set).

The solution set must not contain duplicate subsets. Return the solution in any order.

Example 1

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

Example 2

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

Constraints

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • All the numbers of nums are unique.
View original on LeetCode β†—

Every element is either in a subset or out of it, so a size-n array has 2^n subsets. The two approaches below differ in how they enumerate them.

Bitmask Enumeration

Time O(n Β· 2^n)Space O(n Β· 2^n)

Every subset corresponds to one of the 2^n binary numbers from 0 to 2^n - 1: bit i set means nums[i] is included.

class Solution:
def subsets(self, nums: list[int]) -> list[list[int]]:
n = len(nums)
result = []
for mask in range(1 << n):
result.append([nums[i] for i in range(n) if mask & (1 << i)])
return result

Simple and iterative, but it is really the same brute force as backtracking β€” it just encodes the same β€œin or out” decisions as bits instead of recursive calls. 2^n masks, each built in O(n), giving O(n Β· 2^n) time and space for the output.

Backtracking (Include/Exclude via a Start Index)

OptimalTime O(n Β· 2^n)Space O(n)

Treat the current path as a subset that is already valid on its own β€” add it to the result immediately, then extend it by trying every element after start. Each recursive call decides β€œadd this element, recurse, then remove it” (backtrack) before moving to the next candidate.

class Solution:
def subsets(self, nums: list[int]) -> list[list[int]]:
result = []
path = []
def backtrack(start):
result.append(path[:])
for i in range(start, len(nums)):
path.append(nums[i])
backtrack(i + 1)
path.pop()
backtrack(0)
return result

Tracing nums = [1,2,3] as a decision tree β€” every node visited is itself a complete subset, recorded the instant we arrive:

[]
1 / 7
result

Start with the empty path. It is a valid subset on its own β€” record it immediately.

Complexity: the recursion tree has exactly 2^n nodes (one per subset), each doing O(n) work to copy path into the result β†’ O(n Β· 2^n) time. The path list and recursion depth are bounded by n β†’ O(n) auxiliary space (excluding the output itself).