Partition Equal Subset Sum
Keep one row dp[s]: can some of the numbers seen so far add up to s? Start with only dp[0] = true. For each number x, go from s = half down to x and set dp[s] = dp[s] || dp[s − x]. Going high → low means dp[s − x] still holds the value from before x was added, so x is never used twice.
Two equal groups exist exactly when some subset adds up to total / 2, and dp[half] records whether one does.
Problem
You get a list of positive whole numbers, nums. Can you split the list into two groups so that both groups have the same sum?
Every number goes into exactly one of the two groups. Return true if an equal split is possible, and false if it is not.
An array of positive integers nums.
true if the numbers can be split into two groups with equal sums, otherwise false.
Put 1, 5 and 5 in one group (sum 11). The other group is [11], which also sums to 11.
The total is 11, which is odd. Two equal groups would each need a sum of 5.5, and that is not a whole number.
Put the two 3s in one group (sum 6). The three 2s make the other group, which also sums to 6.
- • 1 ≤ nums.length ≤ 200
- • 1 ≤ nums[i] ≤ 100
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
If the two groups must be equal, what must each group add up to? Can I work that out from the total alone?
- 2.
If the total is odd, can two groups with equal sums exist? What goes wrong?
- 3.
Each number goes in group A or group B. Is that the same kind of choice I make for every number in a subset problem?
- 4.
If one group adds up to the target, what do I know about the other group? Do I need to check it separately?
- 5.
Would the rule 'always add the next number to the lighter group' always give the right answer? Try [3, 3, 2, 2, 2] by hand.
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Take or skip each number; succeed if some subset reaches total / 2 | O(2^N) | O(N) |
| Better | dp[i][s] = can the first i numbers make sum s? Fill it row by row | O(N · S) | O(N · S) |
| Optimal | One true / false row over sums 0 … total / 2; each number updates it from high to low | O(N · S) | O(S) |
Why does this belong to this pattern?
- “split into two groups with equal sums”Each group must reach total / 2. Find one subset with that sum, and the other group is what is left.
- “every number goes into exactly one group”Each number is taken or skipped at most once → 0/1 knapsack, not unbounded.
- “return true or false”We only need to know whether the target can be reached, so one row of true / false values is enough.
This is the anchor of the Partition sub-pattern. The key step is the reduction: two equal groups exist exactly when one subset sums to total / 2, because the other group is whatever is left. An odd total gives false at once, since no whole number is half of it. After that it is plain 0/1 subset sum: each number is used once, so the row is filled high → low. Unlike the Subset Sum questions in the 0/1 sub-pattern, the target is not given. You compute it from the total, so check the total first.
Don't make this mistake
The greedy looks reasonable, but it commits to each number before it has seen the rest. On the dry-run input [3, 3, 2, 2, 2] (total 12, so each group needs 6) it does: 3 → A, 3 → B, 2 → A (5 vs 3), 2 → B (5 vs 5), 2 → A (7 vs 5). It returns false. The answer is true, because [3, 3] and [2, 2, 2] each sum to 6. The table finds it, because dp[6] is set by 3 + 3 before the 2s are even considered.
On [1, 2, 3, 5] the total is 11, and 11 / 2 = 5 in integer division. The subset [5] sums to 5, so the DP returns true. But an odd total can never split into two equal whole sums, so the answer is false.
On [1, 4, 1] the total is 6 and half is 3. Going low → high lets the first 1 be reused: dp[1] = T, then dp[2] = dp[1] = T (1 + 1), then dp[3] = dp[2] = T (1 + 1 + 1). It returns true, but the list has only two 1s, so no group sums to 3 and the answer is false.
Want to implement this?
Write it yourself on LeetCode, 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.