2Brute2Best
🔥0

Partition Equal Subset Sum

Medium·LeetCode #416Basic Anchor
LeetCode
30-Second Mental ModelKnapsack — 0/1 subset sum (partition into two groups)
Complexity:O(2^N)→O(N · S)
Key Insight

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.

Core Validity Invariant

Two equal groups exist exactly when some subset adds up to total / 2, and dp[half] records whether one does.

01

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.

Input

An array of positive integers nums.

Output

true if the numbers can be split into two groups with equal sums, otherwise false.

Example 1
Input: nums = [1, 5, 11, 5]
Output: true

Put 1, 5 and 5 in one group (sum 11). The other group is [11], which also sums to 11.

Example 2
Input: nums = [1, 2, 3, 5]
Output: false

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.

Example 3
Input: nums = [3, 3, 2, 2, 2]
Output: true

Put the two 3s in one group (sum 6). The three 2s make the other group, which also sums to 6.

Constraints
  • • 1 ≤ nums.length ≤ 200
  • • 1 ≤ nums[i] ≤ 100
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 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. 2.

    If the total is odd, can two groups with equal sums exist? What goes wrong?

  3. 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. 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. 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.

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceTake or skip each number; succeed if some subset reaches total / 2O(2^N)O(N)
Betterdp[i][s] = can the first i numbers make sum s? Fill it row by rowO(N · S)O(N · S)
OptimalOne true / false row over sums 0 … total / 2; each number updates it from high to lowO(N · S)O(S)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “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.
split into two equal-sum groups+one subset with sum total / 2+each number used at most once→Knapsack — 0/1 subset sum (partition into two groups)

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.

10

Don't make this mistake

Pattern confusion: the greedy 'lighter group' rule
✗ sort nums from largest to smallest; for (int x : nums) { if (a <= b) a += x; else b += x; } return a == b;
✓ bool dp row over sums 0 … half; return dp[half];

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.

Forgetting the odd check
✗ int half = total / 2; // no odd check, so 11 / 2 = 5
✓ if (total % 2 != 0) return false;

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.

Filling the row low → high
✗ for (int s = x; s <= half; s++) dp[s] = dp[s] || dp[s - x];
✓ for (int s = half; s >= x; s--) dp[s] = dp[s] || dp[s - x];

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.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like DP — Knapsack translate into production architectures and low-level memory mechanics.