Python 动态规划-使用一组整数计算和的方法的数量
我问了这个问题 不太明白那里的答案, 我写了两种方法来解决一个问题: 使用数字N(允许重复)找出可以达到总和S的方法的数量 和=4,数=1,2,3答案是1111,221122,31,131212212212212 在一种方法中我使用备忘录,而在另一种方法中我不使用。不知怎的,在我的机器上,记忆版本比非记忆版本运行得慢 这两种解决方案都有效 备忘录版本:Python 动态规划-使用一组整数计算和的方法的数量,python,algorithm,dynamic-programming,Python,Algorithm,Dynamic Programming,我问了这个问题 不太明白那里的答案, 我写了两种方法来解决一个问题: 使用数字N(允许重复)找出可以达到总和S的方法的数量 和=4,数=1,2,3答案是1111,221122,31,131212212212212 在一种方法中我使用备忘录,而在另一种方法中我不使用。不知怎的,在我的机器上,记忆版本比非记忆版本运行得慢 这两种解决方案都有效 备忘录版本: def find_denomination_combinations(amount, denominations): memo =
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查找面额组合(金额、面额):
备忘录={}
def计算组合(最大金额):
return_list=list()
对于面额中的面额:
新金额=最大金额-面额
如果new_sum==0:
return\u list.append([max\u amt])
返回列表
elif new_sum<0:
返回[]]
其他:
如果备忘录中有新金额:
组合列表=备忘录[新金额]
其他:
组合列表=计算组合(新组合)
对于组合列表中的组合:
如果备忘录中的新金额和组合[:]不在备忘录中[新金额]:
备注[new_sum].追加(组合[:])
其他:
备忘录[新金额]=[]
备注[new_sum].追加(组合[:])
组合。追加(面额)
return\u list.append(组合)
返回列表
结果=计算组合(金额)
返回结果
非记忆版本
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
def find_面额_组合_nmimo(金额、面额):
def计算组合(最大金额):
return_list=list()
对于面额中的面额:
新金额=最大金额-面额
如果new_sum==0:
return\u list.append([max\u amt])
返回列表
elif new_sum<0:
返回[]]
其他:
组合列表=计算组合(新组合)
对于组合列表中的组合:
组合。追加(面额)
return\u list.append(组合)
返回列表
结果=计算组合(金额)
返回结果
我的算法是:
[T(sum-D)],其中D属于给定的整数集
如果输入和=16,整数集=[1,2,3]
非备忘录版本运行时间为0.3秒,备忘录版本运行时间为5秒,我认为备忘录版本速度较慢,因为它使用复杂的代码更新最外层的
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])
这是非常快的。使用此修复程序,在大多数情况下,记忆版本应该比未记忆的代码快
不过,还有其他问题。如果您的面额
列表未按递增顺序排序,或者面额值之间存在间隙,则会得到错误的结果。基本上,任何可能导致elif
案例被命中的情况都会给出错误的结果
以下是针对循环的主体的一个版本,用于纠正这些问题:
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
这稍微慢一点,可能是因为额外的函数调用,但代码要简单得多,没有elif
或else
案例 非常感谢!现在看起来干净多了!我也在想同样的事情,我在这里没有做太多的计算,只是设置和获取,如果这可能会导致速度缓慢。的确
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)