Count of Subsets with a Given Sum
The same table again, one operator further along. `Math.max` became `||` when values became reachability; now `||` becomes `+` because the question changed from *whether* a subset hits the target to *how many* do. Skip and take are disjoint families of subsets, so their counts add — and the base cases flip from `false`/`true` to `0`/`1`, which is the same statement in a different type.
The problem
Implement `countOfSubsetWithGivenSum(nums, target)`: given an array of non-negative integers, return how many distinct subsets sum to exactly `target`. Each number may be used at most once, and subsets are distinguished by position, not value.
`nums = [2, 3, 5, 6, 8, 10], target = 10` returns `3` — `{10}`, `{2, 8}` and `{2, 3, 5}`. `nums = [1, 1, 1], target = 2` returns `3`, not `1`: the three `1`s are different elements even though they look identical, so each pair counts separately.
The approach
Structurally this is `subsetSumProblem` with one substitution. `memo[i][j]` stops meaning 'can the first `i` numbers reach `j`' and starts meaning 'how many ways can they'. The item loop, the capacity loop and the `nums[i-1] <= j` guard are all byte-for-byte the same; only the cell type and the combining operator move.
`skip || take` becomes `skip + take` because the two branches partition the solution space. Every subset that sums to `j` either contains `nums[i-1]` or doesn't — never both, never neither — so the subsets counted by `memo[i-1][j]` and those counted by `memo[i-1][j - nums[i-1]]` are disjoint sets with no overlap to subtract. Addition is exactly right here; it would be wrong the moment an element could be reused, because then the same multiset would be reachable through two paths.
The base cases translate along with the type. `memo[0][j] = 0` — an empty prefix has zero ways to reach a positive sum, which is `false` restated. `memo[i][0] = 1` — every prefix has exactly one way to reach `0`, by taking nothing, which is `true` restated. `memo[0][0]` gets written twice again and the column loop wins again, landing on `1`: there is exactly one empty subset and it sums to zero.
The caveat this formulation hides is zeros in the input. Forcing `memo[i][0] = 1` down the entire column asserts 'one way to make zero' for every prefix, but if `nums` contains a `0`, that element can be in or out of the subset without changing the sum, so a prefix with `k` zeros has `2^k` ways. `[0, 0, 1]` with `target = 1` should be `4` and this returns `1`. Seeding only `memo[0][0] = 1` and letting the recurrence fill the rest of the column fixes it — the `+` doubles at each zero on its own.
The solution
export function countOfSubsetWithGivenSum(nums, target) {
const memo = Array.from({ length: nums.length + 1 }, () =>
Array(target + 1).fill(null),
);
// initialize the first row with 0
for (let j = 0; j <= target; j++) {
memo[0][j] = 0;
}
// initialize the first column with 1
for (let i = 0; i <= nums.length; i++) {
memo[i][0] = 1;
}
// fill the memo table
for (let i = 1; i <= nums.length; i++) {
for (let j = 1; j <= target; j++) {
if (nums[i - 1] <= j) {
memo[i][j] = memo[i - 1][j] + memo[i - 1][j - nums[i - 1]];
} else {
memo[i][j] = memo[i - 1][j];
}
}
}
// return the result
return memo[nums.length][target];
}Time O(n * target)Space O(n * target)