From c93841eb9468cf6433e057a230d60063cfcd1dd8 Mon Sep 17 00:00:00 2001 From: nickzerjeski Date: Sat, 11 Apr 2026 16:18:01 +0200 Subject: [PATCH 1/3] Add space optimized 0/1 knapsack implementation --- dynamic_programming/knapsack.py | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index 28c5b19dbe36..ecdb38e7989c 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -39,6 +39,40 @@ def knapsack(w, wt, val, n): return dp[n][w_], dp +def knapsack_space_optimized( + capacity: int, weights: list[int], values: list[int], num_items: int +) -> int: + """ + Solve the 0/1 knapsack problem with O(capacity) extra space. + + It uses a 1D dynamic programming array and iterates capacities in reverse + for each item to avoid reusing the same item more than once. + + >>> knapsack_space_optimized(50, [10, 20, 30], [60, 100, 120], 3) + 220 + >>> knapsack_space_optimized(0, [10, 20, 30], [60, 100, 120], 3) + 0 + >>> knapsack_space_optimized(6, [4, 3, 2, 3], [3, 2, 4, 4], 4) + 8 + """ + if num_items < 0: + raise ValueError("The number of items cannot be negative.") + if capacity < 0: + raise ValueError("The knapsack capacity cannot be negative.") + if num_items > len(weights) or num_items > len(values): + raise ValueError("The number of items exceeds the provided input lengths.") + + dp = [0] * (capacity + 1) + for item_index in range(num_items): + item_weight = weights[item_index] + item_value = values[item_index] + for current_capacity in range(capacity, item_weight - 1, -1): + dp[current_capacity] = max( + dp[current_capacity], item_value + dp[current_capacity - item_weight] + ) + return dp[capacity] + + def knapsack_with_example_solution(w: int, wt: list, val: list): """ Solves the integer weights knapsack problem returns one of From 07539cb4d9f849628ab46d21c801f9714c4987cb Mon Sep 17 00:00:00 2001 From: nickzerjeski Date: Sat, 11 Apr 2026 16:50:31 +0200 Subject: [PATCH 2/3] Harden knapsack_space_optimized input validation --- dynamic_programming/knapsack.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index ecdb38e7989c..a6500543deec 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -54,6 +54,26 @@ def knapsack_space_optimized( 0 >>> knapsack_space_optimized(6, [4, 3, 2, 3], [3, 2, 4, 4], 4) 8 + >>> knapsack_space_optimized(-1, [1], [1], 1) + Traceback (most recent call last): + ... + ValueError: The knapsack capacity cannot be negative. + >>> knapsack_space_optimized(1, [1], [1], -1) + Traceback (most recent call last): + ... + ValueError: The number of items cannot be negative. + >>> knapsack_space_optimized(1, [1], [1], 2) + Traceback (most recent call last): + ... + ValueError: The number of items exceeds the provided input lengths. + >>> knapsack_space_optimized(1, [-1], [1], 1) + Traceback (most recent call last): + ... + ValueError: Weight at index 0 cannot be negative. + >>> knapsack_space_optimized(1, [1], [1.5], 1) + Traceback (most recent call last): + ... + TypeError: Value at index 0 must be an integer. """ if num_items < 0: raise ValueError("The number of items cannot be negative.") @@ -61,6 +81,15 @@ def knapsack_space_optimized( raise ValueError("The knapsack capacity cannot be negative.") if num_items > len(weights) or num_items > len(values): raise ValueError("The number of items exceeds the provided input lengths.") + for item_index in range(num_items): + item_weight = weights[item_index] + item_value = values[item_index] + if not isinstance(item_weight, int): + raise TypeError(f"Weight at index {item_index} must be an integer.") + if item_weight < 0: + raise ValueError(f"Weight at index {item_index} cannot be negative.") + if not isinstance(item_value, int): + raise TypeError(f"Value at index {item_index} must be an integer.") dp = [0] * (capacity + 1) for item_index in range(num_items): From 3fb7cf30b4a7bc899828eb7eca8e746fb2d0dfb3 Mon Sep 17 00:00:00 2001 From: nickzerjeski Date: Sat, 11 Apr 2026 16:56:26 +0200 Subject: [PATCH 3/3] Fix ruff EM102 in knapsack_space_optimized --- dynamic_programming/knapsack.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index a6500543deec..9d5155cdd7e8 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -85,11 +85,14 @@ def knapsack_space_optimized( item_weight = weights[item_index] item_value = values[item_index] if not isinstance(item_weight, int): - raise TypeError(f"Weight at index {item_index} must be an integer.") + msg = f"Weight at index {item_index} must be an integer." + raise TypeError(msg) if item_weight < 0: - raise ValueError(f"Weight at index {item_index} cannot be negative.") + msg = f"Weight at index {item_index} cannot be negative." + raise ValueError(msg) if not isinstance(item_value, int): - raise TypeError(f"Value at index {item_index} must be an integer.") + msg = f"Value at index {item_index} must be an integer." + raise TypeError(msg) dp = [0] * (capacity + 1) for item_index in range(num_items):