#416 Partition Equal Subset Sum
the problem
In plain words
Can nums be split into two subsets with equal sums?
in nums = [1,5,11,5]
out true
[1,5,5] and [11].
in nums = [1,2,3,5]
out false
- 1 ≤ nums.length ≤ 200
- 1 ≤ nums[i] ≤ 100
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
pattern0/1 knapsack
Two equal halves means one subset sums to exactly total / 2. That's 0/1 knapsack with booleans: can I make sum s using each number at most once?
solutions
From brute force to optimal
canMake(i, target) = canMake(i+1, target − nums[i]) || canMake(i+1, target).
- Odd total → false.
- target = 0 → true; out of numbers → false.
Every number is taken or skipped.
Recursion depth.
class Solution { public boolean canPartition(int[] nums) { int total = Arrays.stream(nums).sum(); if (total % 2 != 0) return false; // odd total can never split evenly return canMake(nums, 0, total / 2); } /** Can some subset of nums[i..] add up to exactly target? */ private boolean canMake(int[] nums, int i, int target) { if (target == 0) return true; if (i == nums.length || target < 0) return false; return canMake(nums, i + 1, target - nums[i]) // take nums[i] || canMake(nums, i + 1, target); // skip nums[i] }}States are (i, target): n × (S + 1), where S = total / 2.
- Boolean[][] memo, null = unknown.
Each state once.
The memo.
class Solution { public boolean canPartition(int[] nums) { int total = Arrays.stream(nums).sum(); if (total % 2 != 0) return false; Boolean[][] memo = new Boolean[nums.length][total / 2 + 1]; // null = unknown return canMake(nums, 0, total / 2, memo); } private boolean canMake(int[] nums, int i, int target, Boolean[][] memo) { if (target == 0) return true; if (i == nums.length || target < 0) return false; if (memo[i][target] != null) return memo[i][target]; return memo[i][target] = canMake(nums, i + 1, target - nums[i], memo) || canMake(nums, i + 1, target, memo); }}dp[i][s] = can the first i numbers make s?
- dp[i][0] = true.
- dp[i][s] = dp[i−1][s] || dp[i−1][s − nums[i−1]].
One step per cell.
The table.
class Solution { public boolean canPartition(int[] nums) { int total = Arrays.stream(nums).sum(); if (total % 2 != 0) return false; int half = total / 2, n = nums.length; boolean[][] dp = new boolean[n + 1][half + 1]; // dp[i][s]: can the first i numbers make s? for (int i = 0; i <= n; i++) dp[i][0] = true; // the empty subset makes 0 for (int i = 1; i <= n; i++) { for (int s = 1; s <= half; s++) { dp[i][s] = dp[i - 1][s]; // skip nums[i-1] if (nums[i - 1] <= s) dp[i][s] |= dp[i - 1][s - nums[i - 1]]; // take it } } return dp[n][half]; }}Same shape: the 0/1 knapsack table
Rolling row; go downward so each number is used at most once.
- dp[0] = true.
- for x: for s = S down to x: dp[s] |= dp[s − x].
- Early exit when dp[S] is true.
n numbers × up to S sums (≤ 200 × 10⁴ = 2·10⁶).
One row.
class Solution { public boolean canPartition(int[] nums) { int total = Arrays.stream(nums).sum(); if (total % 2 != 0) return false; int half = total / 2; boolean[] dp = new boolean[half + 1]; // dp[s]: can some numbers seen so far make s? dp[0] = true; // the empty subset makes 0 for (int x : nums) { for (int s = half; s >= x; s--) { // DOWNWARD: each number used at most once dp[s] = dp[s] || dp[s - x]; // keep s, or reach it by adding x to s - x } if (dp[half]) return true; // early exit } return dp[half]; }}One row, swept downward
in the room
How to say it in the interview
talk track
- "Equal halves ⇔ subset with sum total/2" — say this reduction first; then it's textbook 0/1 knapsack.
traps
- Forgetting the odd-total early exit.
- Upward inner loop reuses the same number twice → false positives.
what they ask next
Follow-ups
Target Sum (LC 494)?
Count subsets with sum (total + target) / 2 — same table with + instead of ||.
Last Stone Weight II (LC 1049)?
Find the reachable subset sum closest to total / 2.
before you submit
Edge cases to test
- Odd total → false at once.
- One number → false (the other half would be empty).
- [3,4,5] → false: 6 = 3 + 3 only if the 3 is reused — exactly the bug an upward loop has.
practise next
Similar problems
- #322Coin ChangeMediumin Dynamic Programming
- #518Coin Change IIMediumin Dynamic Programming
- #78SubsetsMediumin Backtracking