Generate All Subsets Powerset in DSA Java - Time & Space Complexity
When we generate all subsets (powerset) of a set, we want to know how the time needed grows as the set gets bigger.
We ask: How does the work increase when the input size increases?
Analyze the time complexity of the following code snippet.
public void generateSubsets(int[] nums) {
List> result = new ArrayList<>();
backtrack(0, nums, new ArrayList<>(), result);
}
private void backtrack(int start, int[] nums, List current, List> result) {
result.add(new ArrayList<>(current));
for (int i = start; i < nums.length; i++) {
current.add(nums[i]);
backtrack(i + 1, nums, current, result);
current.remove(current.size() - 1);
}
}
This code generates all subsets of the input array by exploring each element's inclusion or exclusion recursively.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls exploring each subset possibility.
- How many times: Each element can be either included or excluded, leading to 2^n subsets.
As the input size grows, the number of subsets doubles for each new element added.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 2^10 = 1,024 subsets |
| 20 | About 2^20 = 1,048,576 subsets |
| 30 | About 2^30 = 1,073,741,824 subsets |
Pattern observation: The work doubles with each additional element, growing exponentially.
Time Complexity: O(n * 2^n)
This means the time grows very fast because we explore all subsets, and each subset can take up to n steps to build.
[X] Wrong: "Generating all subsets is just O(2^n) because there are 2^n subsets."
[OK] Correct: We also spend time copying each subset which can take up to n steps, so the total time is actually O(n * 2^n).
Understanding this complexity helps you explain why generating all subsets is expensive and shows you can analyze recursive algorithms well.
What if we only needed subsets of a fixed size k? How would the time complexity change?
Practice
powerset mean in the context of subsets?Solution
Step 1: Understand the definition of powerset
The powerset of a set is the collection of all possible subsets, including the empty set and the set itself.Step 2: Compare options with definition
All possible subsets of a given set, including empty and full set correctly describes the powerset as all subsets. Other options describe partial or unrelated concepts.Final Answer:
All possible subsets of a given set, including empty and full set -> Option AQuick Check:
powerset = all subsets [OK]
- Thinking powerset excludes empty set
- Confusing powerset with subsets of fixed size
- Assuming powerset means complement sets
Solution
Step 1: Identify return type for all subsets
All subsets of an integer array require returning a list of lists of integers, so return type should be List.Step 2: Check method parameters and return type
public List generateSubsets(int[] nums) matches correct return type and parameter. Options A and C have wrong return types, and D has wrong parameter type.Final Answer:
public List<List<Integer>> generateSubsets(int[] nums) -> Option CQuick Check:
Return type must hold all subsets = List of List [OK]
- Using int return type instead of list
- Using void return type without output
- Passing single int instead of int array
public static List subsets(int[] nums) {
List result = new ArrayList<>();
result.add(new ArrayList<>());
for (int num : nums) {
int size = result.size();
for (int i = 0; i < size; i++) {
List<Integer> subset = new ArrayList<>(result.get(i));
subset.add(num);
result.add(subset);
}
}
return result;
}
// Called with nums = {1, 2}Solution
Step 1: Initialize result with empty subset
Initially, result = [[]].Step 2: Iterate over nums and add new subsets
For num=1, add [1] to result: result = [[], [1]]. For num=2, add [2] and [1,2]: result = [[], [1], [2], [1, 2]].Final Answer:
[[], [1], [2], [1, 2]] -> Option AQuick Check:
All subsets of {1,2} = [[], [1], [2], [1, 2]] [OK]
- Forgetting to include empty subset
- Adding subsets in wrong order
- Missing combined subsets like [1, 2]
public static List subsets(int[] nums) {
List result = new ArrayList<>();
for (int num : nums) {
int size = result.size();
for (int i = 0; i < size; i++) {
List<Integer> subset = new ArrayList<>(result.get(i));
subset.add(num);
result.add(subset);
}
}
result.add(new ArrayList<>());
return result;
}Solution
Step 1: Check when empty subset is added
Empty subset must be added before starting to build subsets, so that initial subsets exist.Step 2: Analyze code flow
Here, empty subset is added after loops, so result.size() is zero initially and inner loop never runs, producing empty result except empty subset at end.Final Answer:
Empty subset is added at the end, should be added before loop -> Option DQuick Check:
Empty subset must be first for subsets to build [OK]
- Adding empty subset after loops
- Incorrect loop ranges causing no subsets
- Returning wrong data type
nums that may contain duplicates, which modification to the standard subsets generation algorithm ensures the powerset contains no duplicate subsets?Solution
Step 1: Understand duplicates in subsets
Duplicates in input cause duplicate subsets if not handled.Step 2: Use sorting and skip duplicates
Sorting groups duplicates together. While generating subsets, skip adding subsets that duplicate the last added subset to avoid duplicates.Final Answer:
Sort the array first and skip adding subsets that duplicate the last added subset -> Option BQuick Check:
Sort + skip duplicates = unique subsets [OK]
- Ignoring duplicates causing repeated subsets
- Using HashSet but forgetting order or conversion
- Assuming duplicates don't affect subsets
Ready to prove it?
Pass the test and this pattern moves unknown
