Subsets Generation Using Bitmask in DSA Python - 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 create subsets using bitmasks?
Analyze the time complexity of the following code snippet.
nums = [1, 2, 3]
subsets = []
n = len(nums)
for mask in range(1 << n):
subset = []
for i in range(n):
if mask & (1 << i):
subset.append(nums[i])
subsets.append(subset)
This code generates all subsets of the list nums using bitmasking.
- Primary operation: The nested loops: outer loop runs over all bitmasks, inner loop checks each bit.
- How many times: Outer loop runs 2n times, inner loop runs n times for each outer iteration.
As input size grows, the number of subsets doubles for each new element, and each subset requires checking all elements.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * 210 = 10,240 |
| 20 | About 20 * 220 = 20,971,520 |
| 30 | About 30 * 230 = 32,212,254,720 |
Pattern observation: The operations grow very fast, doubling with each added element and multiplying by n.
Time Complexity: O(n * 2^n)
This means the time needed grows very quickly as input size increases, because we check every subset and every element.
[X] Wrong: "Generating subsets is just O(2^n) because there are 2^n subsets."
[OK] Correct: We also spend time checking each element for every subset, so the inner loop adds a factor of n, making it O(n * 2^n).
Understanding this complexity helps you explain why generating all subsets is expensive and shows your grasp of nested loops and exponential growth.
"What if we only generated subsets of a fixed size k instead of all sizes? How would the time complexity change?"
Practice
Solution
Step 1: Understand bitmask representation
Each bit in a bitmask represents whether an element is included (1) or excluded (0) in a subset.Step 2: Generate subsets using bitmask
By iterating from 0 to 2^n - 1 (where n is number of elements), all combinations of included/excluded elements are covered, producing all subsets.Final Answer:
All possible subsets of the set -> Option DQuick Check:
Bitmask = subsets generator [OK]
- Thinking bitmask generates only large subsets
- Confusing bitmask with sorting or filtering
- Assuming bitmask generates only even or odd subsets
n?Solution
Step 1: Understand bit shift for 2^n
Using1 << nshifts 1 left by n bits, which equals 2 to the power n.Step 2: Use range to cover all bitmasks
Iterating from 0 to1 << n- 1 covers all subsets represented by bitmasks.Final Answer:
for mask in range(1 << n): -> Option AQuick Check:
1 << n = 2^n range [OK]
- Using multiplication instead of bit shift
- Using n squared or doubled incorrectly
- Confusing range limits
arr = ["a", "b"]
subsets = []
for mask in range(1 << len(arr)):
subset = []
for i in range(len(arr)):
if mask & (1 << i):
subset.append(arr[i])
subsets.append(subset)
print(subsets)Solution
Step 1: Understand bitmask iteration
For arr of length 2, masks go from 0 to 3 (00, 01, 10, 11 in binary).Step 2: Map bits to elements
Mask 0 (00) -> no elements -> [] Mask 1 (01) -> include arr[0] -> ['a'] Mask 2 (10) -> include arr[1] -> ['b'] Mask 3 (11) -> include arr[0], arr[1] -> ['a', 'b']Final Answer:
[[], ['a'], ['b'], ['a', 'b']] -> Option BQuick Check:
Bitmask subsets match output [OK]
- Mixing order of subsets
- Appending elements incorrectly
- Confusing bit positions
arr = [1, 2, 3]
subsets = []
for mask in range(1 << len(arr)):
subset = []
for i in range(len(arr)):
if mask & i:
subset.append(arr[i])
subsets.append(subset)
print(subsets)Solution
Step 1: Analyze bitmask condition
The condition 'mask & i' incorrectly checks bits; it should check if the i-th bit is set using 'mask & (1 << i)'.Step 2: Correct bit checking
Using 'mask & (1 << i)' correctly tests if the bit at position i is 1, indicating inclusion of arr[i].Final Answer:
The condition should be 'mask & (1 << i)' instead of 'mask & i' -> Option CQuick Check:
Bit check needs shift [OK]
- Using 'mask & i' instead of 'mask & (1 << i)'
- Initializing subset outside loop causing accumulation
- Misplacing print inside loops
arr = [1, 2, 2], what is the output of the following code that generates subsets using bitmask?arr = [1, 2, 2]
subsets = []
for mask in range(1 << len(arr)):
subset = []
for i in range(len(arr)):
if mask & (1 << i):
subset.append(arr[i])
subsets.append(subset)
print(subsets)Solution
Step 1: Calculate total subsets
For 3 elements, total subsets = 2^3 = 8, masks from 0 to 7.Step 2: Map each mask to subset
Mask 0 (000): [] Mask 1 (001): [1] Mask 2 (010): [2] (second element) Mask 3 (011): [1, 2] Mask 4 (100): [2] (third element) Mask 5 (101): [1, 2] Mask 6 (110): [2, 2] Mask 7 (111): [1, 2, 2]Final Answer:
[[], [1], [2], [1, 2], [2], [1, 2], [2, 2], [1, 2, 2]] -> Option AQuick Check:
Duplicates appear as separate elements [OK]
- Assuming duplicates merge subsets
- Missing subsets with repeated elements
- Incorrect mask to subset mapping
Ready to prove it?
Pass the test and this pattern moves unknown
