Skip to content

Knapsack

Problem

Given n items, each with a weight and value, and a knapsack with a weight capacity W, choose items to maximize total value without exceeding capacity. Each item can be taken at most once.

Approach

Classic DP. knapsack_2d is the full tabulation (for clarity); knapsack is the space-optimized 1D alternate (iterate capacity backwards to avoid reusing items in the same row).

When to Use

Resource allocation with constraints — "maximize value under weight limit", "subset sum", "budget allocation". 0/1 variant for items used at most once.

Complexity

TimeO(n * W)
SpaceO(n * W) for 2D, O(W) for 1D

Source

"""0/1 Knapsack — maximize value within weight capacity.

Problem:
    Given n items, each with a weight and value, and a knapsack with
    a weight capacity W, choose items to maximize total value without
    exceeding capacity. Each item can be taken at most once.

Approach:
    Classic DP. knapsack_2d is the full tabulation (for clarity);
    knapsack is the space-optimized 1D alternate (iterate capacity
    backwards to avoid reusing items in the same row).

When to use:
    Resource allocation with constraints — "maximize value under weight
    limit", "subset sum", "budget allocation". 0/1 variant for items
    used at most once.

Complexity:
    Time:  O(n * W)
    Space: O(n * W) for 2D, O(W) for 1D
"""

from collections.abc import Sequence


def knapsack_2d(
    weights: Sequence[int],
    values: Sequence[int],
    capacity: int,
) -> int:
    """Return the maximum value achievable using 2D DP table.

    >>> knapsack_2d([1, 3, 4, 5], [1, 4, 5, 7], 7)
    9
    """
    n = len(weights)
    dp = [[0] * (capacity + 1) for _ in range(n + 1)]

    for i in range(1, n + 1):
        w, v = weights[i - 1], values[i - 1]
        for c in range(capacity + 1):
            dp[i][c] = dp[i - 1][c]
            if w <= c:
                dp[i][c] = max(dp[i][c], dp[i - 1][c - w] + v)

    return dp[n][capacity]


# --- space-optimized 1D alternate (rolling array over a 2D table) ---
def knapsack(
    weights: Sequence[int],
    values: Sequence[int],
    capacity: int,
) -> int:
    """Return the maximum value achievable using 1D space optimization.

    >>> knapsack([1, 3, 4, 5], [1, 4, 5, 7], 7)
    9
    """
    dp = [0] * (capacity + 1)

    for w, v in zip(weights, values, strict=True):
        # capacity walked high-to-low so dp[c - w] still holds last row's
        # (item i-1) value -- forward iteration would let one item get
        # counted twice in the same pass (unbounded, not 0/1)
        for c in range(capacity, w - 1, -1):
            dp[c] = max(dp[c], dp[c - w] + v)

    return dp[capacity]
This page lives in git. Anyone can propose an edit. Edit this page View source

Editor-first interview practice. Content is tracked in git, and every packet page links to its source.

built from bb84dc1