All questions

0/1 Knapsack

Premium

0/1 Knapsack

The 0/1 knapsack problem asks you to pack the most valuable subset of items into a bag with a fixed weight limit, where each item is taken whole or left behind — never split, never taken twice (that is the "0/1"). Each item i has a weight weights[i] and a value values[i], given as two parallel arrays. You return the maximum total value you can carry without the combined weight exceeding capacity. It is the textbook example of dynamic programming — see Knapsack problem for background.

Signature

knapsack01(weights, values, capacity)
  // weights[i], values[i]: the weight and value of item i (parallel arrays, same length)
  // capacity: the weight budget of the knapsack
  // -> number: the maximum total value that fits within the budget

Examples

// Items (weight, value): (1,1) (3,4) (4,5) (5,7); budget 7.
// Best pick: the (3,4) and (4,5) items — weight 3 + 4 = 7, value 4 + 5 = 9.
knapsack01([1, 3, 4, 5], [1, 4, 5, 7], 7); // 9
// A bag with no room can hold nothing.
knapsack01([1, 3, 4, 5], [1, 4, 5, 7], 0); // 0
// Every item fits at once, so the answer is the sum of all values.
knapsack01([1, 2, 3], [6, 10, 12], 6); // 28

Notes

  • Parallel arraysweights and values have the same length; weights[i] and values[i] describe the same item i.
  • Each item is 0 or 1 — you take an item once or not at all. You cannot take a fraction of an item, and you cannot take the same item twice.
  • Non-negative integers — assume every weight and the capacity are non-negative integers; values are non-negative too.
  • Return the value, not the items — you return the maximum achievable total value, not which items were chosen.
  • The limit is inclusive — a subset whose total weight equals capacity exactly is allowed.

FAQ

What are the time and space complexity?
Filling the 2D table is O(n × capacity) in both time and space, where n is the number of items — there are (n + 1) × (capacity + 1) cells and each costs constant work. Note this is pseudo-polynomial: it scales with the capacity's numeric value, not the number of digits used to write it.
Why does the 'take' branch read the previous row instead of the current one?
dp[i-1][w - weight] is the best value from items considered before item i, so adding item i's value uses it at most once — that is the '0/1'. Reading the current row dp[i][w - weight] would let the same item be taken repeatedly, which is the unbounded knapsack, a different problem.
Why doesn't a greedy value-per-weight pick work?
Greedy commits to the densest item first, which can block a better combination. For weights [10, 20, 30] and values [60, 100, 120] with capacity 50, greedy grabs the two densest items for 160, but taking the other two fills the bag exactly for 220.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium