From 08bfc1a714658ad89a3b379a6b4d8cf7caab10b6 Mon Sep 17 00:00:00 2001 From: Anik Chand Date: Sun, 29 Mar 2026 10:13:24 +0530 Subject: [PATCH 1/3] Refactor: clean memoized knapsack using functools.cache --- .../knapsack_memoized_clean.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 dynamic_programming/knapsack_memoized_clean.py diff --git a/dynamic_programming/knapsack_memoized_clean.py b/dynamic_programming/knapsack_memoized_clean.py new file mode 100644 index 000000000000..1c9d3ebb28d7 --- /dev/null +++ b/dynamic_programming/knapsack_memoized_clean.py @@ -0,0 +1,42 @@ +from functools import cache + + +def knapsack_memoized(weights: list[int], values: list[int], capacity: int) -> int: + """ + Solve 0/1 knapsack using memoization without global state. + + Args: + weights: list of item weights + values: list of item values + capacity: maximum capacity of knapsack + + Returns: + Maximum achievable value + + >>> knapsack_memoized([1, 3, 4], [10, 20, 30], 4) + 30 + >>> knapsack_memoized([1, 2, 3], [10, 15, 40], 6) + 65 + >>> knapsack_memoized([], [], 5) + 0 + """ + + if len(weights) != len(values): + raise ValueError("weights and values must be of same length") + + n = len(weights) + + @cache + def dp(i: int, remaining: int) -> int: + if i == n or remaining == 0: + return 0 + + if weights[i] > remaining: + return dp(i + 1, remaining) + + return max( + dp(i + 1, remaining), + values[i] + dp(i + 1, remaining - weights[i]), + ) + + return dp(0, capacity) From 0d77dac9b6e295c2ad4cfbc4d51359bfa51f00d6 Mon Sep 17 00:00:00 2001 From: Anik Chand Date: Sun, 29 Mar 2026 10:24:57 +0530 Subject: [PATCH 2/3] Fix: add docstring to dp and improve parameter naming --- .../knapsack_memoized_clean.py | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/dynamic_programming/knapsack_memoized_clean.py b/dynamic_programming/knapsack_memoized_clean.py index 1c9d3ebb28d7..d14b2ae492cd 100644 --- a/dynamic_programming/knapsack_memoized_clean.py +++ b/dynamic_programming/knapsack_memoized_clean.py @@ -1,7 +1,9 @@ from functools import cache -def knapsack_memoized(weights: list[int], values: list[int], capacity: int) -> int: +def knapsack_memoized( + weights: list[int], values: list[int], capacity: int +) -> int: """ Solve 0/1 knapsack using memoization without global state. @@ -19,6 +21,8 @@ def knapsack_memoized(weights: list[int], values: list[int], capacity: int) -> i 65 >>> knapsack_memoized([], [], 5) 0 + >>> knapsack_memoized([2, 3, 4], [4, 5, 6], 0) + 0 """ if len(weights) != len(values): @@ -27,16 +31,29 @@ def knapsack_memoized(weights: list[int], values: list[int], capacity: int) -> i n = len(weights) @cache - def dp(i: int, remaining: int) -> int: - if i == n or remaining == 0: + def dp(index: int, remaining: int) -> int: + """ + Recursive helper function for knapsack memoization. + + Args: + index: current item index + remaining: remaining capacity of knapsack + + Returns: + Maximum value achievable from current state + + Note: + This function is internally tested via knapsack_memoized doctests. + """ + if index == n or remaining == 0: return 0 - if weights[i] > remaining: - return dp(i + 1, remaining) + if weights[index] > remaining: + return dp(index + 1, remaining) return max( - dp(i + 1, remaining), - values[i] + dp(i + 1, remaining - weights[i]), + dp(index + 1, remaining), + values[index] + dp(index + 1, remaining - weights[index]), ) return dp(0, capacity) From 51a0d5c67ac698349bf4a15a01b732587925c491 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 04:55:47 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/knapsack_memoized_clean.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dynamic_programming/knapsack_memoized_clean.py b/dynamic_programming/knapsack_memoized_clean.py index d14b2ae492cd..2b8e13d908aa 100644 --- a/dynamic_programming/knapsack_memoized_clean.py +++ b/dynamic_programming/knapsack_memoized_clean.py @@ -1,9 +1,7 @@ from functools import cache -def knapsack_memoized( - weights: list[int], values: list[int], capacity: int -) -> int: +def knapsack_memoized(weights: list[int], values: list[int], capacity: int) -> int: """ Solve 0/1 knapsack using memoization without global state.