Dynamic Programming · Classic DP Patterns

Subset Sum (Boolean DP)

Building a 1D boolean table where dp[cap] answers "is there a subset of the items considered so far that sums to exactly cap," processing capacities in decreasing order so each item is still only ever used once - the 0/1 knapsack shape specialized to a yes/no reachability question instead of an optimization.

  • 4 min read
  • 8 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: splitting into two equal halves
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Sometimes the question isn't "what's the best subset?" but "does any subset add up to exactly this sum?" Can these payments exactly cover an invoice? Can these items be split into two equal halves? With n numbers there are 2^n subsets, but only target + 1 sums matter, so a boolean table over sums answers the question. This skill covers that table, the partition check, and how to get an actual subset back.

We'll go from simple to more technical:

  1. The pattern: reachable[s], swept downward per number, starting from reachable[0] = true.
  2. A second flavor: splitting into two equal halves (check the parity first).
  3. Where exact-sum checks show up (reconciliation, load balancing).
  4. What breaks it: upward sweeps, the empty subset, odd totals, huge sums.

The approach

Java

boolean subsetSumExists(int[] nums, int target) {
    boolean[] reachable = new boolean[target + 1];
    reachable[0] = true;                               // the empty subset sums to 0
    for (int x : nums) {
        for (int s = target; s >= x; s--) {            // downward: each number used at most once
            if (reachable[s - x]) reachable[s] = true;
        }
    }
    return reachable[target];
}

Python

def subset_sum_exists(nums: list[int], target: int) -> bool:
    reachable = [False] * (target + 1)
    reachable[0] = True                                # the empty subset sums to 0
    for x in nums:
        for s in range(target, x - 1, -1):             # downward: each number used at most once
            if reachable[s - x]:
                reachable[s] = True
    return reachable[target]

After processing some numbers, reachable[s] says whether a subset of them sums to s. A new number x makes s reachable if s - x already was. The downward sweep is the 0/1-knapsack rule: reachable[s - x] must reflect the numbers before x, or x could be used twice - sweeping upward, the single number 5 "reaches" 10. Everything starts from reachable[0] = true; without it nothing is ever reachable.

A second flavor: splitting into two equal halves

Partitioning numbers into two subsets with equal sums is subset sum in disguise: each half must sum to total / 2. So check the total first:

Java

int total = 0;
for (int x : nums) total += x;
if (total % 2 != 0) return false;                  // an odd total can't be halved
return subsetSumExists(nums, total / 2);

Python

def can_partition(nums: list[int]) -> bool:
    total = sum(nums)
    if total % 2 != 0:
        return False                                   # an odd total can't be halved
    return subset_sum_exists(nums, total // 2)

Skipping the parity check is a real bug, not a shortcut: for [1, 2], total / 2 rounds down to 1, which is reachable, so the code would claim a split exists. Replace boolean with a count (ways[s] += ways[s - x]) and the same table counts the subsets instead.

Where you'll see it

Reconciliation (which open invoices add up to this payment?), load balancing across two machines (split jobs so both finish together), and "exact change" checks in payment and gift-card systems are subset-sum questions. In finance reconciliation tools, the reachable-sums table (with parent pointers) also recovers which items match.

Which tool for which job?

You needUse
Does a subset hit the target?a boolean table over sums, swept downward
Two equal halvesparity check, then subset sum to total / 2
The halves as close as possiblethe reachable sum nearest total / 2
The subset itselfa "first reached by" index per sum, walked back
A nonempty subset divisible by k, n ≥ kprefix sums mod k (pigeonhole), O(n)
Many repeated small valuesgroup equal values, then binary splitting
Huge values, n up to about 40meet in the middle

Common mistakes

MistakeWhat happensDo this instead
Sweeping upward[5] reaches 10sweep downward
reachable[0] left falsenothing is ever reachablethe empty subset sums to 0
No parity check[1, 2] "splits" because 3 / 2 rounds to 1an odd total can't be halved
A table for sums near 10^9too largemeet in the middle for small n
The 1D table when the subset is neededthe choices are overwrittenrecord which number first reached each sum

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why sweep s from target down to x?

Show answer

So reachable[s - x] still describes subsets of the earlier numbers. Sweeping upward, it may have just been set using x itself, letting x count twice - [5] with target 10 would be "reachable".

2. [1, 2]: can it be split into two equal-sum subsets? What does the code return without the parity check?

Show answer

No - the total 3 is odd. Without the check, total / 2 = 1 is reachable ({1}), so the code wrongly returns true.

3. How does the table change to count subsets instead of checking existence?

Show answer

Store counts: ways[0] = 1 and ways[s] += ways[s - x], still sweeping downward. The recurrence is identical; OR becomes +.

Key takeaways

  • reachable[s] = some subset of the numbers so far sums to s; reachable[0] = true.
  • For each number, sweep sums downward so it's used at most once.
  • Equal partition = subset sum to total / 2 - after checking the total is even.
  • Counting subsets is the same table with + instead of OR.
  • O(n * target): pseudo-polynomial; huge values need meet-in-the-middle.

Quick revise

The whole skill on one page, for the night before an interview.

This page puts the lesson and the deep dive together. Skim it before practice or an interview, and go back to the full lesson for anything you don't recognize.

Pick the tool

You needUse
Hit the target?boolean table, downward
Equal halvesparity check plus subset sum
Closest halvesreachable sum nearest total / 2
The subsetfirst[s], walked back
Divisible by k, n ≥ kprefix sums mod k
Repeated small valuesgroup plus binary splitting

Snippets worth knowing by heart

Java

boolean[] reach = new boolean[target + 1];
reach[0] = true;                                      // the empty subset
for (int x : nums)
    for (int s = target; s >= x; s--)                 // downward: each number once
        if (reach[s - x]) reach[s] = true;

Python

seen, s = {0: -1}, 0                     # nonempty block with sum divisible by k
for i, x in enumerate(nums):
    s = (s + x) % k
    if s in seen:
        return nums[seen[s] + 1:i + 1]
    seen[s] = i

The traps

  • Upward sweep: one 5 reaches 10 by being used twice. Sweep downward.
  • reach[0] left false: nothing is ever reachable. The empty subset sums to 0.
  • No parity check: [1, 2] "splits" because 3 / 2 rounds to 1. An odd total can't be halved.
  • Huge sums: a table for sums near 10^9 can't exist. Meet in the middle when n is small.

Staff-level points, one line each

  • first[s] rebuilt a valid subset exactly when one existed, on 500 cases, in O(target) space.
  • The nearest reachable sum to total / 2 gave the smallest split difference, matching brute force on 300 arrays.
  • With n ≥ k numbers, a block divisible by k always exists. For k = 7 it found [17, 4], which sums to 21.
  • 10,000 values between 1 and 100 reduced to 700 0/1 items.
  • 3-partition is NP-complete even for small numbers.

Say it in an interview

  • "reachable[s] over sums, swept downward, starting from the empty subset."
  • "For partition I check the parity first."
  • "To recover the subset I store which number first reached each sum."
  • "If there are at least k numbers, a block divisible by k is guaranteed."

Practice

This skill comes with 8 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Subset Sum (Boolean DP) free

Subset Sum Equal to Target

MediumProCoding problemJava · Python

Given an array of non-negative integers nums and a non-negative integer target, return whether some subset of nums sums exactly to target.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Partition Equal Subset Sum

MediumProCoding problemJava · Python

Can nums be split into two groups with equal totals, every number going into exactly one group? Return whether it can.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Subset Sum (Boolean DP) free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime