DSA Notes
Generate all subsets (power set) using backtracking and bit manipulation — understand the include/exclude pattern and enumerate 2^n possibilities efficiently.
Problem Statement
Given a set of N distinct elements, generate all possible subsets (the power set). For a set of size N, there are exactly 2^N subsets, ranging from the empty set to the full set itself.
The Include/Exclude Intuition
For every element in the set, you make a binary decision: include it in the current subset or exclude it. This creates a binary decision tree of depth N, where each leaf corresponds to one unique subset.
Think of it like a buffet line with N dishes. At each dish, you either put it on your plate or skip it. By the end of the line, your plate holds one particular subset of all available dishes. Walk through the line 2^N times making every possible combination of yes/no decisions, and you get the entire power set.
All 2³ = 8 subsets are generated at the leaves.
Approach 1: Backtracking (Include/Exclude)
Approach 2: Iterative Expansion (Cascading)
Start with [[]]. For each element, take all existing subsets and create new subsets by appending the element:
Approach 3: Bit Manipulation
Each subset maps to a binary number from 0 to 2^N - 1. If bit i is set, element i is included.
Approach 4: Backtracking with "Choose Next" Pattern
Instead of include/exclude, at each step choose which element to add next (only picking from elements after the current index to avoid duplicates):
This generates subsets in lexicographic order and is the most common interview pattern.
C++ Implementation
Handling Duplicates
When the input contains duplicates (e.g., [1, 2, 2]), sort first, then skip consecutive equal elements at the same recursion level:
Dry Run: Subsets of {A, B, C} with Choose-Next
| i=0: add A | backtrack(1, [A]) |
| i=1: add B | backtrack(2, [A,B]) |
| i=2: add C | backtrack(3, [A,B,C]) |
| i=2: add C | backtrack(3, [A,C]) |
| i=1: add B | backtrack(2, [B]) |
| i=2: add C | backtrack(3, [B,C]) |
| i=2: add C | backtrack(3, [C]) |
| Final | [], [A], [A,B], [A,B,C], [A,C], [B], [B,C], [C] |
Complexity Analysis
| Approach | Time | Space | Notes |
|---|---|---|---|
| Backtracking | O(N × 2^N) | O(N) stack | N factor for copying each subset |
| Bitmask | O(N × 2^N) | O(1) extra | Simple loop, cache-friendly |
| Iterative | O(N × 2^N) | O(N × 2^N) | Stores all subsets in memory |
The 2^N factor is unavoidable since we must output 2^N subsets, each of average size N/2.
Subsets vs Combinations vs Permutations
| Problem | Count | Order matters? | Pattern |
|---|---|---|---|
| Subsets | 2^N | No | Include/exclude all elements |
| Combinations (k items) | C(N,k) | No | Subsets of fixed size k |
| Permutations | N! | Yes | All orderings |
For combinations of size k, simply add a length check: only record when len(current) == k.
Real-World Applications
- Feature selection in ML: Try all subsets of features to find best model
- Test case generation: Enumerate combinations of configuration flags
- Resource allocation: Consider all possible subsets of tasks to assign
- Cryptanalysis: Enumerate possible key combinations
- Set cover problem: Evaluate which subsets cover all elements
Key Takeaways
Subset generation is foundational to combinatorial algorithms. The include/exclude pattern gives a clean binary tree, the choose-next pattern gives lexicographic order, and bitmask enumeration is the fastest for competitive programming. When duplicates exist, sort and skip. Every subset problem in interviews reduces to one of these templates.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Subset Generation.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, backtracking, subset, generation
Related Data Structures & Algorithms Topics