[英]Dynamic Programming - Number of ways to calculate sum using a set of integers
我經歷了這個問題
添加到具有N個數字的和S的 方法的 數量 查找從給定集合求和給定數量(允許重復)的所有方法
不太明白那里的答案,
我寫了兩個方法來解決一個問題:
找到使用數字N(允許重復)達到總和S的方式的數量
例如。 sum = 4和number = 1,2,3 answer是1111,22,1122,31,13,1212,2112,2212
在一種方法中我使用memoization而在另一種方法中我沒有。 在我的機器中,memoize版本的運行速度比非memoized版本慢
這兩種解決方案都有效。
記憶版:
def find_denomination_combinations(amount, denominations):
memo = {}
def calculate_combinations(max_amt):
return_list = list()
for denomination in denominations:
new_sum = max_amt - denomination
if new_sum == 0:
return_list.append([max_amt])
return return_list
elif new_sum < 0:
return [[]]
else:
if new_sum in memo:
combi_list = memo[new_sum]
else:
combi_list = calculate_combinations(new_sum)
for combination in combi_list:
if new_sum in memo and combination[:] not in memo[new_sum]:
memo[new_sum].append(combination[:])
else:
memo[new_sum] = []
memo[new_sum].append(combination[:])
combination.append(denomination)
return_list.append(combination)
return return_list
result = calculate_combinations(amount)
return result
非記憶版
def find_denomination_combinations_nmemo(amount, denominations):
def calculate_combinations(max_amt):
return_list = list()
for denomination in denominations:
new_sum = max_amt - denomination
if new_sum == 0:
return_list.append([max_amt])
return return_list
elif new_sum < 0:
return [[]]
else:
combi_list = calculate_combinations(new_sum)
for combination in combi_list:
combination.append(denomination)
return_list.append(combination)
return return_list
result = calculate_combinations(amount)
return result
我的算法是:
每個D的[T(sum-D)],其中D屬於給定的整數集合
如果輸入sum = 16且整數組= [1,2,3]
非記憶版本在0.3秒內運行,記憶版本需要5秒鍾
我相信memoized版本比較慢,因為復雜的代碼,它使用更新的最備忘錄字典else
塊。 它可以更簡單:
if new_sum in memo:
combi_list = memo[new_sum]
else:
combi_list = memo[new_sum] = calculate_combinations(new_sum)
for combination in combi_list:
return_list.append(combination + [denomination])
這要快得多。 使用此修復程序,在大多數情況下,memoized版本應該比非memoized代碼更快。
但是還有其他問題。 如果您的denominations
列表沒有按遞增順序排序或者面額值之間存在差距,您將得到錯誤的結果。 基本上,任何可能導致elif
案件被擊中的情況都會給出錯誤的結果。
這是for
循環體的一個版本, for
糾正這些問題:
new_sum = max_amt - denomination
if new_sum == 0:
return_list.append([max_amt]) # don't return here, to allow unsorted denominations!
elif new_sum > 0:
if new_sum in memo:
combi_list = memo[new_sum]
else:
combi_list = memo[new_sum] = calculate_combinations(new_sum)
for combination in combi_list:
return_list.append(combination + [denomination])
# do nothing for new_amt < 0
您可以通過使每個調用在備忘錄中保存自己的結果,而不是依賴其調用者來執行此操作,並將基本案例邏輯(對於new_sum == 0
)與new_sum == 0
相結合,從而進一步簡化操作。 我還重命名或刪除了幾個變量:
def find_denomination_combinations_blckknght(amount, denominations):
memo = {0: [[]]} # prefill value for base case of calculate_combinations where amt==0
def calculate_combinations(amt):
if amt not in memo:
memo[amt] = []
for denomination in denominations:
new_amt = amt - denomination
if new_amt >= 0:
for combination in calculate_combinations(new_amt):
memo[amt].append(combination + [denomination])
# do nothing for new_amt < 0
return memo[amt]
return calculate_combinations(amount)
這有點慢,可能是因為額外的函數調用,但代碼更簡單,沒有elif
或else
任何else
情況!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.