Subsets Generation Using Bitmask in DSA Java - Time & Space Complexity
We want to understand how the time needed to generate all subsets grows as the input size increases.
How does the number of operations change when we have more elements to create subsets from?
Analyze the time complexity of the following code snippet.
public List> subsets(int[] nums) {
int n = nums.length;
List> result = new ArrayList<>();
for (int mask = 0; mask < (1 << n); mask++) {
List subset = new ArrayList<>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0) {
subset.add(nums[i]);
}
}
result.add(subset);
}
return result;
}
This code generates all possible subsets of the input array using bitmasking.
- Primary operation: Two nested loops: outer loop runs over all bitmasks, inner loop checks each bit.
- How many times: Outer loop runs 2^n times; inner loop runs n times for each outer iteration.
As input size grows, the number of subsets doubles, and for each subset, we check each element.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * 2^10 = 10,240 operations |
| 20 | About 20 * 2^20 = 20,971,520 operations |
| 30 | About 30 * 2^30 = 32,212,254,720 operations |
Pattern observation: Operations grow very fast, doubling with each added element and multiplied by the element count.
Time Complexity: O(n * 2^n)
This means the time needed grows exponentially with the number of elements, multiplied by the number of elements checked each time.
[X] Wrong: "Generating subsets is just O(2^n) because there are 2^n subsets."
[OK] Correct: Each subset requires checking up to n elements to build it, so the total work is n times 2^n, not just 2^n.
Understanding this complexity helps you explain why generating all subsets is expensive and shows your grasp of exponential growth in algorithms.
"What if we used recursion instead of bitmasking? How would the time complexity change?"
Practice
Solution
Step 1: Understand bitmask representation
Each bit in the bitmask represents whether an element is included (1) or excluded (0) in a subset.Step 2: Generate subsets using bitmask
By iterating through all bitmasks from 0 to 2^n - 1, we get all possible subsets of the set.Final Answer:
All possible subsets of the set -> Option AQuick Check:
Bitmask = subsets generator [OK]
- Thinking bitmask generates only largest subsets
- Confusing bitmask with subsets of fixed size
- Ignoring subsets with zero elements
arr of length n using bitmask?Solution
Step 1: Understand bitmask range
Bitmask runs from 0 to 2^n - 1, which is (1 << n) in Java.Step 2: Check loop syntax
The loop must start at 0 and run while mask is less than (1 << n), so for (int mask = 0; mask < (1 << n); mask++) is correct.Final Answer:
for (int mask = 0; mask < (1 << n); mask++) -> Option DQuick Check:
Loop from 0 to 2^n - 1 [OK]
- Starting loop from 1 instead of 0
- Using <= n instead of < 2^n
- Confusing n with 2^n in loop condition
int[] arr = {1, 2};
for (int mask = 0; mask < (1 << arr.length); mask++) {
System.out.print("{");
for (int i = 0; i < arr.length; i++) {
if ((mask & (1 << i)) != 0) {
System.out.print(arr[i] + " ");
}
}
System.out.print("} ");
}Solution
Step 1: Understand bitmask values
arr.length = 2, so mask goes from 0 to 3 (0b00 to 0b11).Step 2: Trace each mask iteration
mask=0 (0b00): no bits set, prints {}
mask=1 (0b01): bit 0 set, prints {1 }
mask=2 (0b10): bit 1 set, prints {2 }
mask=3 (0b11): bits 0 and 1 set, prints {1 2 }Final Answer:
{ } {1 } {2 } {1 2 } -> Option AQuick Check:
Bitmask subsets printed in order [OK]
- Mixing order of subsets
- Printing subsets without braces
- Confusing bit positions with array indices
int[] arr = {1, 2, 3};
for (int mask = 0; mask <= (1 << arr.length); mask++) {
for (int i = 0; i < arr.length; i++) {
if ((mask & (1 << i)) > 0) {
System.out.print(arr[i] + " ");
}
}
System.out.println();
}Solution
Step 1: Check loop range correctness
mask runs from 0 to 2^n - 1, so mask < (1 << arr.length) is correct. Using <= causes one extra iteration beyond valid range.Step 2: Verify bitwise condition and loops
(mask & (1 << i)) > 0 is valid to check if bit is set. Inner loop from 0 to arr.length is correct.Final Answer:
Loop condition should be mask < (1 << arr.length), not <=. -> Option CQuick Check:
Loop must not exceed 2^n - 1 [OK]
- Using <= causes out-of-range mask
- Incorrect bitwise condition operators
- Starting inner loop at 1 instead of 0
arr = {1, 2, 3, 4}, how many subsets generated by bitmask will have an even sum of elements?Solution
Step 1: Calculate total subsets
For 4 elements, total subsets = 2^4 = 16.Step 2: Count subsets with even sum
Half of the subsets of a set with consecutive integers have even sum. So, 16 / 2 = 8 subsets.Final Answer:
8 -> Option BQuick Check:
Half subsets have even sum for consecutive integers [OK]
- Counting total subsets as answer
- Assuming all subsets have even sum
- Miscounting subsets with odd sums
Ready to prove it?
Pass the test and this pattern moves unknown
