I have been spending way too much time on a programming challenge:
Given a budget and a set of prices, compute all unique combinations on how to spend the entire budget.
budget = 100
prices = [25, 50]
[[25, 25, 25, 25], [25, 25, 50], [25, 50, 25], [50, 25, 25], [50, 50]]
I have implemented a brute force solution in Python that works correctly:
def spend_the_budget(budget: int, prices: list) -> list:
if budget == 0:
return [[]]
if budget < 0:
return None
combinations = []
for price in prices:
remainder = budget - price
remainder_combinations = spend_the_budget(remainder, prices)
if remainder_combinations is not None:
for remainder_combination in remainder_combinations:
remainder_combination += [price]
combinations.append(remainder_combination)
return combinations
However, this has obviously exponential time complexity and therefore doesn't scale in an acceptable fashion. Therefore I'd like to add memoization but can't seem to get it to work:
def spend_the_budget_memoized(budget: int, prices: list, memo: dict = {}) -> list:
if budget in memo:
return memo[budget]
if budget == 0:
return [[]]
if budget < 0:
return None
combinations = []
for price in prices:
remainder = budget - price
remainder_combinations = spend_the_budget_memoized(remainder, prices, memo)
if remainder_combinations is not None:
for remainder_combination in remainder_combinations:
remainder_combination += [price]
combinations.append(remainder_combination)
memo[budget] = combinations
return combinations
Weirdly enough however, this yields an incorrect result and I just can't wrap around my head as to what I did wrong here:
[[25, 25, 25, 50, 25, 25, 50], [50, 25, 25, 50], [25, 25, 25, 50, 25, 25, 50], [25, 25, 25, 50, 25, 25, 50], [50, 25, 25, 50]]
for remainder_combination in remainder_combinations:
remainder_combination += [price]
combinations.append(remainder_combination)
When you iterate over remainder_combinations
you are iterating over the same copy which is stored in memo
. Use list.copy() instead,
for remainder_combination in remainder_combinations:
temp = remainder_combination.copy()
temp += [price]
combinations.append(temp)