Bird
Raised Fist0
Interview Prepsubsets-combinationsmediumAmazonFacebookGoogleMicrosoft

Subsets

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
📋
Problem

Imagine you have a set of unique ingredients and want to explore every possible combination to create new recipes.

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.

1 ≤ nums.length ≤ 20-10^6 ≤ nums[i] ≤ 10^6All elements of nums are unique
Edge cases: Empty input array → output [[]]Single element array → output [[], [element]]All elements are negative → subsets still valid
</>
IDE
def subsets(nums: list[int]) -> list[list[int]]:public List<List<Integer>> subsets(int[] nums)vector<vector<int>> subsets(vector<int>& nums)function subsets(nums)
def subsets(nums: list[int]) -> list[list[int]]:
    # Write your solution here
    pass
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        // Write your solution here
        return new ArrayList<>();
    }
}
#include <vector>
using namespace std;

vector<vector<int>> subsets(vector<int>& nums) {
    // Write your solution here
    return {};
}
function subsets(nums) {
    // Write your solution here
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: [[1,2,3]]Only including all elements subset, missing empty and partial subsets.Add recursion branch to exclude current element at each step.
Wrong: []Not adding empty subset or missing base case when index == len(nums).Add current subset to result when index == len(nums).
Wrong: [[], [10]]Only one subset returned for single element input, missing either include or exclude branch.Ensure both include and exclude recursive calls are made for each element.
Wrong: Subsets with duplicates when input has duplicatesInput duplicates cause duplicate subsets; code assumes unique input.Enforce input uniqueness or skip duplicates during recursion.
Wrong: Missing subsets due to greedy approachGreedy approach skips exclude branch causing incomplete subsets.Explore both include and exclude branches at each recursion step.
Test Cases
t1_01basic
Input{"nums":[1,2,3]}
Expected[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

Starting from empty set, we either include or exclude each element, generating all subsets.

t1_02basic
Input{"nums":[4,5]}
Expected[[],[4],[5],[4,5]]

All subsets of [4,5] generated by including or excluding each element.

t2_01edge
Input{"nums":[]}
Expected[[]]

Empty input array returns only the empty subset.

t2_02edge
Input{"nums":[10]}
Expected[[],[10]]

Single element array produces empty subset and subset with that element.

t2_03edge
Input{"nums":[-1,-2,-3]}
Expected[[],[-1],[-2],[-1,-2],[-3],[-1,-3],[-2,-3],[-1,-2,-3]]

Negative numbers are valid elements; subsets generated normally.

t3_01corner
Input{"nums":[1,2,2]}
Expected[[],[1],[2],[1,2],[2,2],[1,2,2]]

Input with duplicates (invalid per constraints) to catch if code assumes uniqueness.

t3_02corner
Input{"nums":[1,2,3,4]}
Expected[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3],[4],[1,4],[2,4],[1,2,4],[3,4],[1,3,4],[2,3,4],[1,2,3,4]]

Tests if code mistakenly uses greedy approach that picks only some subsets.

t3_03corner
Input{"nums":[1,2,3]}
Expected[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

Test to catch off-by-one errors in recursion index handling.

t4_01performance
Input{"nums":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]}
⏱ Performance - must finish in 2000ms

n=20, O(2^n * n) subsets generation must complete within 2 seconds.

Practice

(1/5)
1. You are given a list of candidate numbers (which may contain duplicates) and a target sum. You need to find all unique combinations where each candidate number is used at most once and the sum of the combination equals the target. Which algorithmic approach best guarantees finding all unique combinations without duplicates efficiently?
easy
A. Backtracking with sorting candidates, skipping duplicates at the same recursion level, and pruning branches when the candidate exceeds the remaining target
B. Greedy algorithm that picks the largest candidates first until the target is met or exceeded
C. Dynamic programming subset-sum approach without handling duplicates explicitly
D. Brute force recursion without sorting or duplicate checks, exploring all subsets

Solution

  1. Step 1: Understand problem constraints

    The problem requires unique combinations without reuse and no duplicate results, so duplicates must be handled carefully.
  2. Step 2: Identify suitable algorithm

    Backtracking with sorting and skipping duplicates at the same recursion level ensures no repeated combinations. Early pruning avoids unnecessary recursion when candidates exceed the target.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Sorting + duplicate skipping + pruning is the standard approach [OK]
Hint: Sorting and skipping duplicates avoids repeated combinations [OK]
Common Mistakes:
  • Using greedy misses some combinations
  • DP without duplicate handling outputs duplicates
  • Brute force is correct but inefficient and duplicates appear
2. Consider the following Python function that counts subsets with sum K using a space-optimized DP approach. What is the output when called with arr = [1, 2, 3, 3] and K = 6?
def count_subsets_space_optimized(arr, K):
    dp = [0] * (K + 1)
    dp[0] = 1
    for num in arr:
        for j in range(K, num - 1, -1):
            dp[j] += dp[j - num]
    return dp[K]

print(count_subsets_space_optimized(arr, K))
easy
A. 5
B. 4
C. 3
D. 6

Solution

  1. Step 1: Initialize dp array

    dp = [1,0,0,0,0,0,0] since dp[0]=1 and K=6.
  2. Step 2: Process each number updating dp

    After processing 1: dp = [1,1,0,0,0,0,0] After 2: dp = [1,1,1,1,0,0,0] After first 3: dp = [1,1,1,2,1,1,1] After second 3: dp = [1,1,1,3,2,2,3]
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    dp[6] = 5 subsets sum to 6 [OK]
Hint: Trace dp updates backward to avoid double counting [OK]
Common Mistakes:
  • Forgetting to iterate backward in dp array
  • Off-by-one errors in dp indices
3. You are given an unsorted array of positive integers. Your task is to find the largest subset such that for every pair (Si, Sj) in the subset, either Si divides Sj or Sj divides Si. Which algorithmic approach guarantees finding the optimal solution efficiently?
easy
A. Greedy approach by always picking the smallest element and adding divisible elements afterwards
B. Use a brute force backtracking to generate all subsets and check divisibility
C. Sort the array and use dynamic programming to build the longest chain where each element divides the next
D. Use a graph traversal to find the largest clique where edges represent divisibility

Solution

  1. Step 1: Understand problem constraints

    The problem requires a subset where every pair is divisible in one direction, which suggests a chain-like structure.
  2. Step 2: Identify suitable algorithm

    Sorting the array allows divisibility checks to be done efficiently in increasing order, enabling dynamic programming to build the longest divisible chain.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Sorting + DP is classic for largest divisible subset [OK]
Hint: Sort + DP builds longest divisible chain [OK]
Common Mistakes:
  • Greedy fails because local choices don't guarantee global maximum
  • Brute force is correct but inefficient, not practical
  • Graph clique approach is incorrect because divisibility is not symmetric
4. Given the following code to generate subsets, what is the value of result after processing num=2 when nums = [1, 2]?
easy
A. [[], [1], [2]]
B. [[], [1], [1, 2], [2]]
C. [[], [1], [2], [1, 2], [2, 2]]
D. [[], [1], [2], [1, 2]]

Solution

  1. Step 1: Trace result after processing num=1

    Initially result = [[]]. After num=1, new_subsets = [[1]], result = [[], [1]].
  2. Step 2: Trace result after processing num=2

    For each subset in [[], [1]], add 2: new_subsets = [[2], [1, 2]]. Extend result: [[], [1], [2], [1, 2]].
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    All subsets of [1,2] are present exactly once [OK]
Hint: Iterative subsets double result size each iteration [OK]
Common Mistakes:
  • Forgetting to add subsets with current num
  • Appending duplicates
  • Wrong order of subsets
5. The following code attempts to solve Combination Sum (Reuse Allowed). Identify the line containing the subtle bug that causes incorrect results or inefficiency:
def combinationSum(candidates, target):
    candidates.sort()
    result = []
    def backtrack(index, path, target):
        if target == 0:
            result.append(path[:])
            return
        if index == len(candidates) or target < 0:
            return
        max_use = target // candidates[index]
        for count in range(max_use + 1):
            path += [candidates[index]] * count
            backtrack(index + 1, path, target - candidates[index] * count)
            # Missing path restoration here
    backtrack(0, [], target)
    return result
medium
A. Line with 'path += [candidates[index]] * count' because path is modified without backtracking (pop).
B. Line with 'candidates.sort()' because sorting is unnecessary.
C. Line with 'if target == 0:' because it should check for target <= 0.
D. Line with 'max_use = target // candidates[index]' because integer division may cause errors.

Solution

  1. Step 1: Analyze path modification in loop

    Path is extended by count copies of candidates[index] but never restored after recursive call, causing path to grow incorrectly across iterations.
  2. Step 2: Identify missing backtracking step

    Proper backtracking requires removing added elements after recursion to restore path state for next iteration.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Modifying path without restoration leads to incorrect combinations [OK]
Hint: Always restore path after recursion in backtracking [OK]
Common Mistakes:
  • Forgetting to pop elements after recursion
  • Assuming path copy avoids mutation issues