Partition Equal Subset Sum asks whether an array can be split into two groups with the same total. It looks like a "try all combinations" problem, but it is really a classic 0/1 knapsack in disguise — and a single boolean array solves it fast.
Problem. Given an array of positive integers nums, return true if you can split it into two
subsets whose sums are equal, and false otherwise. Each element must go into exactly one subset.
Example: nums = [1, 5, 11, 5] → true. The total is 22, so each half must sum to 11: the subsets
{11} and {1, 5, 5} both reach 11.
The slow way first
The brute-force idea: try every possible subset and check if its sum equals half the total. With n
elements there are 2ⁿ subsets, so this is O(2ⁿ) — hopeless for anything but tiny arrays.
The reframe that unlocks it: if the total is S, the two halves each need to sum to S / 2. So the real
question is just can any subset reach exactly target = S / 2? If S is odd, no split is possible and we
can answer false immediately.
The idea: track which sums are reachable
Keep a boolean array dp where dp[t] means "some subset reaches sum t". Start with dp[0] = True
(the empty subset sums to 0). Then fold in each number one at a time: a number num lets us reach any sum
t whose remainder t - num was already reachable, so dp[t] = dp[t] or dp[t - num].
The one subtlety: iterate t from target downward to num. Going downward means each number is used
at most once per sum — if we went upward, dp[t - num] could already include num from this same pass,
letting us reuse an element.
Walk through it
Step through the animation. The dp row starts with only dp[0] True. As we fold in 1, then 5, then 11,
more sums light up. The moment we process 11, dp[11] = dp[0] flips True — the target is reachable, so the
answer is yes.
Pseudocode
total = sum(nums)
if total is odd: # cannot split an odd total evenly
return false
target = total / 2
dp = array of False, size target+1
dp[0] = true # empty subset reaches sum 0
for each num in nums:
for t from target down to num:
dp[t] = dp[t] or dp[t - num]
return dp[target]The Python solution
def can_partition(nums):
total = sum(nums)
if total % 2 == 1:
return False
target = total // 2
dp = [True] + [False] * target
for num in nums:
for t in range(target, num - 1, -1):
dp[t] = dp[t] or dp[t - num]
return dp[target]total = sum(nums); if it is odd, no equal split exists, so we bail out early.target = total // 2is the sum each subset must hit.dp[0]isTrue(empty subset), every other entry startsFalse.- The outer loop folds in one
numat a time — each element gets one chance to be used. - The inner loop goes downward (
target→num) so eachnumis counted at most once per sum. dp[t] = dp[t] or dp[t - num]says:tis reachable if it already was, or ift - numwas.- The answer is
dp[target]— did any subset hit exactly half the total?
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (all subsets) | O(2ⁿ) (moderate) | every subset tried |
| Boolean dp (this solution) | O(n × target) (moderate) | n nums, each scans the dp row |
O(target) (moderate)We trade a one-dimensional boolean array (O(target) space) for an enormous speed win: exponential down to
pseudo-polynomial O(n × target). This is the standard 0/1 knapsack shape — one item dimension, one
capacity dimension.
When this pattern shows up
Whenever a problem asks "can we pick a subset that hits exactly some total" — equal partition, subset sum, the coin/target problems — think 0/1 knapsack with a boolean (or count) dp row. The signature move is the inner loop running downward so each item is used at most once.
The downward inner loop is load-bearing. If you scan t from low to high instead, dp[t - num] may already
reflect using num in this same pass, which would let one element be used multiple times — that solves a
different (unbounded) problem.
Practice
For nums = [1, 5, 11, 5], the total is 22 so target = 11. After folding in just 1 and 5, which sums are reachable?
1. What does dp[t] represent in this solution?
2. Why do we return False immediately when the total is odd?
3. Why does the inner loop iterate t from target down to num?
4. What is the time complexity, with n numbers and target = total / 2?