Back to Bit Manipulation
Subset Generation
Subset Generation (Bitmasking)
š§© Problem Statement
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.
This problem specifically asks to be solved using Bit Manipulation (Bitmasking).
š¹ 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]]
š Approaches
1. Bitmasking
- Concept: A subset can be represented by a binary mask of length
N, where the $i$-th bit is1if the $i$-th element is included, and0otherwise. - Total Subsets: There are $2^N$ possible subsets, corresponding to numbers from
0to2^N - 1. - Algorithm:
- Iterate
maskfrom0to2^N - 1. - For each
mask, verify bitsjfrom0toN-1. - If the $j$-th bit is set (
(mask >> j) & 1), includenums[j]in the current subset. - Add the subset to the result.
ā³ Time & Space Complexity
- Time Complexity: $O(N \cdot 2^N)$. We generate $2^N$ subsets, and for each, we iterate $N$ bits.
- Space Complexity: $O(N \cdot 2^N)$ to store the output.
š Code Implementations
C++
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
int totalSubsets = 1 << n; // 2^n
vector<vector<int>> res;
for (int mask = 0; mask < totalSubsets; ++mask) {
vector<int> subset;
for (int i = 0; i < n; ++i) {
// Check if i-th bit is set
if ((mask >> i) & 1) {
subset.push_back(nums[i]);
}
}
res.push_back(subset);
}
return res;
}
};
Python
from typing import List
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
total_subsets = 1 << n
res = []
for mask in range(total_subsets):
subset = []
for i in range(n):
# Check if i-th bit is set
if (mask >> i) & 1:
subset.append(nums[i])
res.append(subset)
return res
Java
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
int totalSubsets = 1 << n;
List<List<Integer>> res = new ArrayList<>();
for (int mask = 0; mask < totalSubsets; mask++) {
List<Integer> subset = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (((mask >> i) & 1) == 1) {
subset.add(nums[i]);
}
}
res.add(subset);
}
return res;
}
}
š Real-World Analogy
Light Switches:
Imagine N light switches (representing elements). Each unique combination of ON/OFF switches creates a distinct lighting "scene" (subset). Iterating through all binary numbers is like systematically flipping through every possible switch configuration.
šÆ Summary
ā
Binary Correspondence: Every integer maps uniquely to a subset.
ā
Iterative vs Recursive: This is the iterative alternative to the classic backtracking solution.
Solution Code
O(n) TimeO(1) Space
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<int>> subsets(vector<int> &nums) {
int n = nums.size();
int totalSubsets = 1 << n;
vector<vector<int>> res;
for (int mask = 0; mask < totalSubsets; ++mask) {
vector<int> subset;
for (int i = 0; i < n; ++i) {
if ((mask >> i) & 1) {
subset.push_back(nums[i]);
}
}
res.push_back(subset);
}
return res;
}
};
int main() {
Solution sol;
vector<int> nums = {1, 2, 3};
vector<vector<int>> res = sol.subsets(nums);
cout << "Test Case 1 (Size should be 8): " << res.size() << endl;
// Print all subsets
for (const auto &sub : res) {
cout << "[";
for (int i = 0; i < sub.size(); ++i) {
cout << sub[i] << (i < sub.size() - 1 ? "," : "");
}
cout << "] ";
}
cout << endl;
return 0;
}
SYSTEM STABLEUTF-8 ⢠STATIC_RENDER