Count Subsets with Sum
Keep one row dp[s] for every sum. For each number x, run dp[s] += dp[s − x] for s from target down to x. Going downward means dp[s − x] is still the count from before x was used, so each number is used at most once.
dp[s − x] must be the count from before x was used. That is why s goes from high to low: then every cell we read is still the old value.
Problem
You get an array arr of numbers and a number target. Count the subsets whose numbers add up to exactly target.
A subset is picked by position. Each number is either in the subset or out of it. So [1, 1] has two different subsets with sum 1: one for each 1. The empty subset counts too, and its sum is 0.
Return the count. GFG's function returns an int and its tests keep the count small enough; the code here also takes the count modulo 10^9 + 7 so that big inputs (many zeros double the count each time) can never overflow.
arr, a list of non-negative integers (zeros are allowed), and target, an integer.
The number of subsets whose sum is target.
The subsets {5, 2, 3}, {2, 8} and {10} add up to 10.
The subsets are {3}, {1, 2}, {0, 3} and {0, 1, 2}. The zero can join any subset without changing its sum, so it doubles the count.
Each 1 sits at its own position, so {first 1} and {second 1} are two different subsets.
The subsets are {1, 2, first 3}, {1, 2, second 3} and {first 3, second 3}.
- • 1 ≤ arr.size() ≤ 10^3
- • 0 ≤ arr[i], target ≤ 10^3
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
If I add a 0 to a subset, does its sum change? What does that do to the count?
- 2.
For one number, how many choices do I have? For N numbers, how many subsets are there in total?
- 3.
If I split the subsets that reach sum s by whether they contain the last number, what do I know about each group?
- 4.
Am I asked whether a subset exists, or how many subsets exist? Does that change what each cell should store?
- 5.
When I process the numbers one at a time, which earlier results do I still need after I finish a number?
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Recurse on each number: leave it out or take it in; count the paths that end at the target | O(2^N) | O(N) |
| Better | dp[i][s] counts the subsets of the first i numbers that sum to s; each cell reads two cells above | O(N · X) | O(N · X) |
| Optimal | Keep one row dp[s]; for each number add dp[s − x] into dp[s], going from the target down to x | O(N · X) | O(X) |
Why does this belong to this pattern?
- “count the subsets”The answer is a number of ways, not a yes or no. Add the ways together; do not take a max or OR.
- “numbers that add up to target”Each number is a 0/1 choice: in or out. The chosen numbers must sum to target.
- “each number can be used at most once”Each item is used once, so the sum loop goes high → low, as in 0/1 Knapsack.
This is the anchor of Count ways. It uses the same 0/1 table as Subset Sum, but each cell adds counts with + where Subset Sum asks yes or no with OR. The loop order is the same as 0/1 Knapsack: sums go from high to low. Target Sum and Profitable Schemes change what the sum or the state means, but they keep this adding rule.
Don't make this mistake
The OR line is the yes/no Subset Sum table. On arr = [1, 2, 3, 0] with target 3, the OR version ends with true, so it returns 1, not 4. A count needs the cells added.
Going up lets dp[s − x] already include x, so x is used again. This is the unbounded Knapsack loop. On arr = [1, 2, 3, 0] with target 3, it returns 6, not 4.
A zero can be in or out of every subset, so every count must double. On arr = [1, 2, 3, 0] with target 3, skipping the zero returns 2, not 4.
With every cell at 0, nothing is ever added, so the answer is 0 for every input. The empty subset is what starts every count.
Want to implement this?
Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like DP — Knapsack translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.