Refactor memoized knapsack implementation to remove global state#14535
Refactor memoized knapsack implementation to remove global state#14535nickzerjeski wants to merge 4 commits intoTheAlgorithms:masterfrom
Conversation
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Pull request overview
Refactors the memoized 0/1 knapsack implementation to remove reliance on global mutable state by using an lru_cache-backed solver closure, while keeping the public mf_knapsack(i, wt, val, j) API.
Changes:
- Replaced global DP-table memoization in
mf_knapsack()with a per-calllru_cache-memoized inner solver and added input validation + doctests. - Fixed
knapsack()to returndp[n][w](avoids incorrect/undefinedw_usage). - Added/adjusted type hints for knapsack-related helpers and simplified the
__main__example by removing obsolete global table initialization.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dynamic_programming/knapsack.py
Outdated
| from functools import lru_cache | ||
|
|
||
|
|
||
| def mf_knapsack(i: int, wt: list[int], val: list[int], j: int) -> int: |
There was a problem hiding this comment.
The mf_knapsack() annotations are more restrictive than the implementation: it only relies on len() + indexing and immediately converts wt/val to tuples, so tuples (and other Sequence types) work too. Consider widening the types to collections.abc.Sequence[int] to match actual supported inputs (this pattern is already used elsewhere, e.g. dynamic_programming/max_subarray_sum.py:16).
| from functools import lru_cache | |
| def mf_knapsack(i: int, wt: list[int], val: list[int], j: int) -> int: | |
| from collections.abc import Sequence | |
| from functools import lru_cache | |
| def mf_knapsack(i: int, wt: Sequence[int], val: Sequence[int], j: int) -> int: |
|
|
||
| return dp[n][w_], dp | ||
| return dp[n][w], dp | ||
|
|
There was a problem hiding this comment.
knapsack_with_example_solution() validates that wt/val are either lists or tuples, but the updated signature still annotates them as list. Consider annotating them as collections.abc.Sequence[int] (or list[int] | tuple[int, ...]) so the type hints align with the function's documented/validated inputs (see dynamic_programming/max_subarray_sum.py:16 for the existing Sequence[...] pattern).
Summary
This PR refactors
mf_knapsack()indynamic_programming/knapsack.pyto remove the global DP table and usefunctools.lru_cachefor memoization.What Changed
global f) with an internal cached solver closure.mf_knapsack(i, wt, val, j)public API intact.mf_knapsack().finitialization from the__main__example.knapsack()return indexing to usewdirectly (dp[n][w]) for correctness and clarity.Why
Issue #14464 requests a cleaner memoized knapsack implementation without global mutable state, with improved readability, typing, and doctests.
Using
lru_cache:Validation
python -m doctest -v dynamic_programming/knapsack.py(pass)pytest -q knapsack/tests/test_knapsack.pycould not run in this environment (pytestnot installed)uv run pytest -q knapsack/tests/test_knapsack.pycould not run in this environment (uvnot installed)Issue
Closes #14464