LeetCode 416 · Medium · 1-D Dynamic Programming

Partition Equal Subset Sum

Can the numbers in nums be split into two groups with the same total? Every number goes into exactly one group.

O(n · sum)time
O(sum)space
reachable sumshit sum / 2

comma-separated · 1–10 numbers · 1 to 20 each · total at most 60

nums walked from the right, as the code does

dp as a row cell t is T when some subset of the numbers seen so far sums to t · sums above target are left out

public boolean canPartition(int[] nums) { int sum = 0; for (int x : nums) { sum += x; } if (sum % 2 != 0) { return false; } Set<Integer> dp = new HashSet<>(); dp.add(0); int target = sum / 2; for (int i = nums.length - 1; i >= 0; i--) { Set<Integer> nextDP = new HashSet<>(); for (int t : dp) { if (t + nums[i] == target) { return true; } nextDP.add(t + nums[i]); nextDP.add(t); } dp = nextDP; } return false;}
target
—
i, nums[i]
—
dp.size()
—
dp (sorted)
—

Why it works

  1. Brute force tries every subset: 2ⁿ ways to choose one group, each summed: exponential.
  2. Only the target matters: two equal groups each total sum / 2, so the question becomes "does some subset sum to target?". An odd total answers false at once.
  3. Grow the set of reachable sums: before any number, only 0 is reachable. Each new number x keeps every old sum (skip x) and adds every old sum plus x (take it). The arcs show that shift by x.
  4. Cost: the set never holds more than sum + 1 values, and each number touches each once: O(n · sum) time, O(sum) space. That is pseudo-polynomial: fine for small totals, slow for huge ones.
  5. Pitfall: adding into the set you are looping over reuses a number twice (and a HashSet throws ConcurrentModificationException). That is why the code builds nextDP. With a boolean array, loop t downward for the same reason.
  6. Related: this is 0/1 knapsack on sums. Target Sum and Last Stone Weight II reduce to the same reachable-sums idea.