Can a subset reach the target?
Given positive integers nums and a non-negative target, return true if some subset
of nums (each element used at most once) sums to exactly target. The empty subset sums to 0.
Examples
| Input | Output | Why |
|---|---|---|
nums = [3,34,4,12,5,2], target = 9 | true | 4 + 5. |
nums = [3,34,4,12,5,2], target = 30 | false | No subset adds to 30. |
nums = [2,4,6], target = 5 | false | Only even totals are reachable. |
Constraints
- 1 ≤ nums.length ≤ 200
- 1 ≤ nums[i] ≤ 100
- 0 ≤ target ≤ 10⁴
Hints
Hint 1
reach[t] = can some subset of the numbers seen so far sum to t? reach[0] = true.
Hint 2
For each number x: reach[t] |= reach[t − x], for t from target down to x.
Hint 3
Downwards, so each number is used at most once.
Where people lose marks
- Iterating totals upwards, which lets one number be used repeatedly.
- Exponential backtracking without memoisation.
Dry run on [3,34,4,12,5,2],9
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 / 7reachT0·1·2·3·4·5·6·7·8·9
Only 0 is reachable with no numbers.
-
Step 2 / 7reachT0·1·2T3·4·5·6·7·8·9
Allow 3: newly reachable 3.
-
Step 3 / 7reachT0·1·2T3·4·5·6·7·8·9
Allow 34: newly reachable nothing.
-
Step 4 / 7reachT0·1·2T3T4·5·6T7·8·9
Allow 4: newly reachable 4, 7.
-
Step 5 / 7reachT0·1·2T3T4·5·6T7·8·9
Allow 12: newly reachable nothing.
-
Step 6 / 7reachT0·1·2T3T4T5·6T7T8T9
Allow 5: newly reachable 5, 8, 9.
-
Step 7 / 7reachT0·1T2T3T4T5T6T7T8T9
Allow 2: newly reachable 2, 6. reach[9] = true.
How to think about it
The 0/1 knapsack with "or" as the operator. Keep reach[t] for every total up to the target, starting with
only reach[0] true. Each number x makes every total t reachable whose remainder t − x was already
reachable without it. Iterating t downwards guarantees that reach[t − x] refers to subsets that do not yet
contain x.
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 subset_sum(nums, target):
reach = [True] + [False] * target # reach[t]: some subset sums to t
for x in nums:
for t in range(target, x - 1, -1): # downwards: x used at most once
if reach[t - x]:
reach[t] = True
return reach[target]#include <vector>
bool solve(const std::vector<int>& nums, int target) {
std::vector<bool> reach(target + 1, false);
reach[0] = true;
for (int x : nums)
for (int t = target; t >= x; --t) // downwards
if (reach[t - x]) reach[t] = true;
return reach[target];
}class Solution {
public boolean subsetSum(int[] nums, int target) {
boolean[] reach = new boolean[target + 1];
reach[0] = true;
for (int x : nums)
for (int t = target; t >= x; t--) // downwards
if (reach[t - x]) reach[t] = true;
return reach[target];
}
}function subsetSum(nums, target) {
const reach = [true, ...new Array(target).fill(false)];
for (const x of nums)
for (let t = target; t >= x; t--) if (reach[t - x]) reach[t] = true; // downwards
return reach[target];
}fn solve(nums: &[i64], target: i64) -> bool {
let target = target as usize;
let mut reach = vec![false; target + 1];
reach[0] = true;
for &x in nums {
let x = x as usize;
if x > target {
continue;
}
for t in (x..=target).rev() { // downwards
if reach[t - x] {
reach[t] = true;
}
}
}
reach[target]
}import qualified Data.Set as S
solve :: [Int] -> Int -> Bool
solve nums target = S.member target (foldl add (S.singleton 0) nums)
where
-- every reachable total, with or without x (capped at the target)
add reach x = S.union reach (S.fromList [t + x | t <- S.toList reach, t + x <= target])
Variants to try
- Count the subsets (sum instead of or).
- Return the subset itself.
- Very large targets but few numbers: meet in the middle, O(2^(n/2)).
Next problems
Split into two equal halves
Can the numbers be divided into two groups with the same sum? Only if half the total is reachable by some subset.
Open the problem → Medium20 minThe smallest difference between two groups
Divide numbers into two groups so the sums are as close as possible. Find the reachable subset sum nearest to half the total.
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
Split into two equal halves
Can the numbers be divided into two groups with the same sum? Only if half the total is reachable by some subset.
Open the problem → Medium20 minThe smallest difference between two groups
Divide numbers into two groups so the sums are as close as possible. Find the reachable subset sum nearest to half the total.
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.