Pattern #73
Subset Sum
Determine if a subset of elements can form an exact target sum. Learn why empty sets make dp[0] = true, why 1D loops MUST run backwards (Right-to-Left), and how Partition Equal Subset Sum maps to Subset Sum.
Must Solve
15 core questions — solve these first.
- 1.Subset SumBoolean 0/1 DP: dp[s] = dp[s] || dp[s - num] updated backwardsmedium
- 2.Partition Equal Subset SumCheck total sum even; solve Subset Sum for target = sum/2medium
- 3.Target SumTransform P = (total + target)/2; count subsets with sum Pmedium
- 4.Last Stone Weight IIFind max subset sum S1 <= total/2; final diff = total - 2*S1medium
- 5.Minimum Subset Sum DifferenceFind largest reachable S1 <= total/2; min diff = total - 2*S1medium
- 6.Count Subsets With Given Sum0/1 counting DP: dp[s] += dp[s - num] updated backwardsmedium
- 7.Number of Subsets With Given DifferenceCount subsets for target sum S1 = (total + diff)/2medium
- 8.Equal Sum PartitionBoolean Subset Sum mapping for half total summedium
- 9.Split Array Into Two Equal Sum SetsCheck if total is even and subset sum target = sum/2 is reachablemedium
- 10.Ones and Zeroes — multi-capacity relationMulti-dimensional 0/1 Subset Sum DP: dp[z][o] updated backwardsmedium
- 11.Tallest Billboard — advanced relationState difference DP: dp[diff] tracking max lower heighthard
- 12.Matchsticks to Square — related partition thinkingBacktracking / Bitmask DP partitioning array into 4 equal sidesmedium
- 13.Partition to K Equal Sum Subsets — advancedBacktracking with Bitmask DP partitioning array into K equal sum subsetsmedium
- 14.Closest Subsequence Sum — advancedMeet-in-the-Middle split N/2 + binary search for closest targethard
- 15.Meet-in-the-Middle Subset SumSplit array into 2 halves (N <= 40) when target T is hugehard
Also Important
5 advanced Subset Sum variations worth practicing.
- 16.Subset Sum Using BitsetBitwise shift: dp |= (dp << num) for 64x parallel speeduphard
- 17.Return One Valid SubsetBacktrack 2D matrix: compare dp[i][s] == dp[i-1][s] to recover itemsmedium
- 18.Count Number of Valid SubsetsSubset sum counting DP with zeroes handlingmedium
- 19.Minimum Number of Elements to Reach TargetUnbounded or 0/1 min items count DPmedium
- 20.Subset Sum With Large Target — alternative approachesMeet-in-the-Middle, Bitset, or Hash Set reachability comparisonhard
How to Think
Each number is usable ONCE. Iterate target backwards (Right -> Left).
- Need to choose some elements to make target?Subset Sum DP
- Each number usable only once?0/1 Knapsack (Right-to-Left loop)
- Need only possible / impossible?Boolean DP (dp[s] = dp[s] || dp[s-num])
- Using 1D DP array?Loop target RIGHT -> LEFT (sum = target down to num)
- Base Case for Target 0?dp[0] = true (empty set sum = 0)
Go Quick Reference — Subset Sum
Compilable Go code demonstrating Boolean 1D Subset Sum (Right-to-Left loop) and Partition Equal Subset Sum.
package main
import "fmt"
// Subset Sum 1D Boolean DP: O(N * Target) time, O(Target) space
func subsetSum(nums []int, target int) bool {
dp := make([]bool, target+1)
dp[0] = true // Base case: Empty set has sum 0
for _, num := range nums {
// RIGHT-TO-LEFT LOOP: prevents using num twice!
for s := target; s >= num; s-- {
if dp[s-num] {
dp[s] = true
}
}
}
return dp[target]
}
// Partition Equal Subset Sum: Check even total sum + Subset Sum
func canPartition(nums []int) bool {
totalSum := 0
for _, num := range nums { totalSum += num }
if totalSum%2 != 0 {
return false // Odd total sum can never be divided equally
}
return subsetSum(nums, totalSum/2)
}
func main() {
nums := []int{1, 5, 11, 5}
fmt.Println("Subset Sum (Target 11):", subsetSum(nums, 11)) // Output: true
fmt.Println("Can Equal Partition:", canPartition(nums)) // Output: true
}👉 Subset Sum: O(N × Target) time and O(Target) boolean array space.
Core Subset Mechanics & Reachable Set Expansion
Why Base Case dp[0] = true
• An empty set {} always has sum 0.
• dp[0] = true acts as the seed from which all subsequent element sums expand!
Reachable Set Mental Model
• Start: {0}.
• Add 2: {0, 2}.
• Add 3: {0, 2, 3, 5}.
Updating backwards (s = target down to num) prevents new sums from expanding twice in the same step.
Subset Sum Base Case -> dp[0] = true (Empty Set Sum = 0)
1D Array Update -> Loop target s = target down to num (Right-to-Left)
Partition Equal Subset Sum -> Target = total / 2 (Check total%2 == 0)
Last Stone Weight II / Min Diff -> Target = largest S1 <= total / 2; ans = total - 2*S1
Target Sum -> Target Positive Sum P = (total + target) / 2
Bitset Optimization -> dp |= (dp << num) for 64x parallel speedupSubset Sum Variants & Advanced Optimizations
Boolean vs Counting Combine Operation
• Boolean Reachability: dp[s] = dp[s] || dp[s - num].
• Counting Subsets: dp[s] = dp[s] + dp[s - num].
• Zero handling: Each zero in counting doubles the number of valid subset choices.
Bitset & Meet-in-the-Middle Optimizations
• Bitset Optimization: reachable |= (reachable << num) shifts all sums in parallel.
• Meet-in-the-Middle: When N <= 40 and target T is huge (e.g. 10⁹): split N into two N/2 halves + binary search.
Reconstructing Chosen Subset Elements
To recover chosen elements from 2D DP matrix dp[N][Target]:
Backtrack from i = N, s = Target:
• If dp[i-1][s] is true: Element i can be SKIPPED.
• Else: Element i was TAKEN -> record nums[i-1] and set s -= nums[i-1].
Common Interview Mistakes
- • Iterating 1D target loop forwards (Left-to-Right), accidentally reusing the same number multiple times.
- • Forgetting base case initialization dp[0] = true (empty set sum = 0), leaving all states unreachable.
- • Failing to check odd total sum in Partition Equal Subset Sum (odd sum can never be divided by 2).
- • Mishandling zero values in Subset Sum counting (zeroes double valid subset count choices).
- • Assuming classic 0...target boolean DP works with negative numbers without index offset shifting.
- • Confusing Subset Sum (each number used once) with Coin Change (coins reusable unlimited times).
- • Attempting 1D target DP when target T = 10^9 without checking constraint bounds (causes Memory Limit Exceeded).
- • Assuming element order matters (subsets [2,3] and [3,2] represent the exact same subset selection).
- • Building full DP table when target > totalSum (impossible to form sum larger than all numbers combined).
Interview Rules
Choose elements to reach exact target? → Subset Sum DP
Rule 1 → Define dp[s] boolean state meaning explicitly
Rule 2 → Base Case: dp[0] = true (empty set sum = 0)
Rule 3 → 1D Array: Loop target s = target down to num (Right-to-Left)
Rule 4 → Partition Equal Subset: Target = total / 2 (Odd sum = false)
Rule 5 → Target Sum: Positive subset target P = (total + target) / 2
Rule 6 → Massive T = 10^9: Use Meet-in-the-Middle or Bitset optimization
Time Complexity → O(N * Target) (Pseudo-Polynomial)
Space Complexity → O(N * Target) 2D Table or O(Target) 1D Boolean Array💡 Golden Rule: Track which sums are reachable, and for each number update those sums backwards so that the current number can contribute at most once.
Production Thinking
Budget Feasibility Auditing → Subset Sum verifies whether any combination of line items exactly matches an allocated budget.
Indivisible Resource Packing → Subset Sum determines if fixed memory/storage blocks can fulfill exact capacity requirements.
Financial Transaction Reconciliation → Subset Sum identifies matching transaction subsets explaining target accounting balances.
Production warning → target T scaling directly impacts array size; for massive target limits (T > 10⁶), switch to Bitset or Meet-in-the-Middle.
Remember This
Subset Sum Goal: Can any element subset sum to target?
Base Case: dp[0] = true (Empty Set Sum = 0)
1D Array: Loop Target RIGHT-TO-LEFT (s = target down to num)
Partition Equal Subset: Target = total / 2
Target Sum: Target positive subset sum P = (total + target) / 2
Bitset Acceleration: reachable |= (reachable << num)
Pseudo-Polynomial: Time = O(N * T), Space = O(T)