Subsets with a given sum
Given non-negative integers nums and a target, return the number of subsets (chosen by position,
so equal values at different positions are different elements) whose sum is target. The empty subset sums to
0.
Examples
| Input | Output | Why |
|---|---|---|
nums = [1,1,2,3], target = 4 | 3 | {1, 3} with either 1, and {1, 1, 2}. |
nums = [1,2,3,4,5], target = 5 | 3 | {5}, {1, 4}, {2, 3}. |
nums = [0,0,1], target = 1 | 4 | Each 0 may be included or not. |
Constraints
- 1 ≤ nums.length ≤ 100
- 0 ≤ nums[i] ≤ 1000
- 0 ≤ target ≤ 10⁴
- The answer fits in a 64-bit integer
Hints
Hint 1
ways[t] = number of subsets of the elements seen so far that sum to t; ways[0] = 1.
Hint 2
For each element x, for t downwards: ways[t] += ways[t − x].
Hint 3
Zeros double every count: the downward loop handles them if it includes t = x = 0 correctly.
Where people lose marks
- Iterating upwards, which reuses elements.
- Mishandling zeros (each zero should double the count).
Dry run on [1,1,2,3],4
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 5ways1001020304
The empty subset sums to 0.
-
Step 2 / 5ways1011020304
Element 1: ways[t] += ways[t − 1], totals downwards.
-
Step 3 / 5ways1021120304
Element 1: ways[t] += ways[t − 1], totals downwards.
-
Step 4 / 5ways1021222314
Element 2: ways[t] += ways[t − 2], totals downwards.
-
Step 5 / 5ways1021223334
Element 3: ways[t] += ways[t − 3], totals downwards. 3 subsets sum to 4.
How to think about it
The 0/1 knapsack with sum as the operator. Process elements one at a time; each either joins a subset or not, so the new
count for total t is the old count plus the old count for t − x. Iterating t downwards keeps the "old" values available
in a single array. A zero needs care: it doubles every count, which in a one-array loop means
ways[t] += ways[t], so update t = 0 last (the downward loop does exactly that).
Complexity. Time O(n · target) · Space O(target)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def count_subsets(nums, target):
ways = [1] + [0] * target # ways[t]: subsets of the elements so far summing to t
for x in nums:
for t in range(target, x - 1, -1): # downwards: x used at most once
ways[t] += ways[t - x]
return ways[target]#include <vector>
long long solve(const std::vector<int>& nums, int target) {
std::vector<long long> ways(target + 1, 0);
ways[0] = 1;
for (int x : nums)
for (int t = target; t >= x; --t) ways[t] += ways[t - x]; // downwards
return ways[target];
}class Solution {
public long countSubsets(int[] nums, int target) {
long[] ways = new long[target + 1];
ways[0] = 1;
for (int x : nums)
for (int t = target; t >= x; t--) ways[t] += ways[t - x]; // downwards
return ways[target];
}
}function countSubsets(nums, target) {
const ways = [1, ...new Array(target).fill(0)];
for (const x of nums) for (let t = target; t >= x; t--) ways[t] += ways[t - x]; // downwards
return ways[target];
}fn solve(nums: &[i64], target: i64) -> i64 {
let n = target as usize;
let mut ways = vec![0i64; n + 1];
ways[0] = 1;
for &x in nums {
let x = x as usize;
if x > n {
continue;
}
for t in (x..=n).rev() {
ways[t] += ways[t - x]; // downwards
}
}
ways[n]
}solve :: [Int] -> Int -> Int
solve nums target = foldl add (1 : replicate target 0) nums !! target
where
-- new[t] = old[t] + old[t - x]: x is either left out or put in
add old x = zipWith (+) old (replicate x 0 ++ old)
Variants to try
- Target sum with + and − signs: count subsets summing to (total + target) / 2.
- Return the subsets.
- Answer modulo 10⁹ + 7.
Next problems
Ordered ways to reach a total
Count the ordered sequences of numbers, each usable any number of times, that sum to a target. The same loops as coin change, swapped.
Open the problem → Medium20 minDice rolls with a target sum
Roll n dice with k faces each. In how many ways can the faces add up to the target? Exactly n picks, so the number of dice used is part of the state.
Open the problem → Easy10 minThe cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem →Write a solution and run it against the real test table.
Keep going
Ordered ways to reach a total
Count the ordered sequences of numbers, each usable any number of times, that sum to a target. The same loops as coin change, swapped.
Open the problem → Medium20 minDice rolls with a target sum
Roll n dice with k faces each. In how many ways can the faces add up to the target? Exactly n picks, so the number of dice used is part of the state.
Open the problem → Easy10 minThe cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem → Dynamic programmingThe pattern behind it
Write the recursion, notice the repeats, fill a table in an order that makes each entry final.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.