Skip to content
ΣDSA Patterns
Menu
Language

Pattern #24

Knapsack & Subset DP

Advanced

Choose items under a capacity or hit an exact sum/target.

When to use

0/1 choices of items with weights/values, partition equal subset, target sum with +/-.

Recognition cues

  • Partition equal subset sum
  • Target sum / coin change II
  • Boolean reachable dp[cap]

Common pitfalls

  • 0/1 vs unbounded loop order (backward vs forward)
  • Half-sum overflow when total is odd
  • Using 2D when 1D reverse iteration is enough

90-second recognition drill

Which pattern fits best?

  • Partition equal subset sum
  • Target sum / coin change II
  • Boolean reachable dp[cap]

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
0
1
2
3
4
5

dp[c] = best value

0/1 knapsack, capacity 5, items (2,3) and (3,4).

How to think about it

dp[c] = best value (or reachable bool) with capacity c. For 0/1, iterate capacity downward so each item is used once. For unbounded, iterate upward. Subset-sum is knapsack with value=weight and bool OR.

Template shapes

Shape Core move Notes
0/1 knapsack c from W down to w dp[c]=max(dp[c], dp[c-w]+v)
Unbounded c from w to W Coins, combos
Subset sum bool dp Partition / target

Complexity baseline

O(n·W) time and O(W) space for classic knapsack.

From template to problem

  1. Identify 0/1 vs unbounded.
  2. Set capacity W (often sum/2).
  3. Init dp[0]=0 or true; fill per item.
  4. Read dp[W] or count of ways.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Knapsack & Subset DP · Template
/** Knapsack template: partition equal subset sum (0/1 bool DP). */
export function canPartition(nums: number[]): boolean {
  const sum = nums.reduce((a, b) => a + b, 0);
  if (sum % 2) return false;
  const target = sum / 2;
  const dp = new Array<boolean>(target + 1).fill(false);
  dp[0] = true;
  for (const x of nums) {
    for (let c = target; c >= x; c--) dp[c] = dp[c]! || dp[c - x]!;
  }
  return dp[target]!;
}
/** Knapsack template: partition equal subset sum (0/1 bool DP). */
export function canPartition(nums: number[]): boolean {
  const sum = nums.reduce((a, b) => a + b, 0);
  if (sum % 2) return false;
  const target = sum / 2;
  const dp = new Array<boolean>(target + 1).fill(false);
  dp[0] = true;
  for (const x of nums) {
    for (let c = target; c >= x; c--) dp[c] = dp[c]! || dp[c - x]!;
  }
  return dp[target]!;
}
#StatusProblemTypeDone
  1. 1#416 Partition Equal Subset SumGuide
  2. 2#474 Ones and ZeroesGuide
  3. 3#494 Target SumGuide
  4. 4#518 Coin Change IIGuide
  5. 5#879 Profitable SchemesGuide
  6. 6#1049 Last Stone Weight IIGuide