我在Python中创建了一个算法,用于计算获得不同硬币面额的金额的方式:
@measure
def countChange(n, coin_list):
maxIndex = len(coin_list)
def count(n, current_index):
if n>0 and maxIndex>current_index:
c = 0
current = coin_list[current_index]
max_coeff = int(n/current)
for coeff in range(max_coeff+1):
c+=count(n-coeff*current, current_index+1)
elif n==0: return 1
else: return 0
return c
return count(n, 0)
我的算法使用索引来获取硬币面额,正如您所看到的,我的索引在我进入的每个堆栈帧中都在增加。我意识到算法也可以用这种方式编写:
@measure
def countChange2(n, coin_list):
maxIndex = len(coin_list)
def count(n, current_index):
if n>0 and 0<=current_index:
c = 0
current = coin_list[current_index]
max_coeff = int(n/current)
for coeff in range(max_coeff+1):
c+=count(n-coeff*current, current_index-1)
elif n==0: return 1
else: return 0
return c
return count(n, maxIndex-1)
这一次,索引正在减少我进入的每个堆栈帧。我比较了函数的执行时间,我得到了一个非常值得注意的区别:
print(countChange(30, range(1, 31)))
print(countChange2(30, range(1, 31)))
>> Call to countChange took 0.9956174254208345 secods.
>> Call to countChange2 took 0.037631815734429974 secods.
如果我甚至没有缓存结果,为什么算法的执行时间会有很大差异?为什么索引的增加顺序会影响执行时间?
答案 0 :(得分:12)
根据我的理解,这与动态编程没有任何关系。只是扭转指数不应该做出“动态”的事情。
发生的事情是该算法输入敏感。尝试以相反的顺序输入输入。例如,
print(countChange(30, list(reversed(range(1, 31)))))
print(countChange2(30, list(reversed(range(1, 31)))))
正如一些排序算法对已经排序的数据非常快,而且反转数据非常慢,你在这里得到了那种算法。
在输入增加的情况下,countChange
需要更多迭代才能得出最终答案,因此看起来要慢得多。但是,当输入减少时,性能特征会反转。
答案 1 :(得分:8)
数字组合并不大
原因是前进你必须探索所有可能性,但是当你倒退时你可以消除大块无效的解决方案,而不必实际计算它们
继续你打电话数500k次
向后退你的代码只会拨打30k电话来计算...
您可以通过记忆调用(或更改算法以不重复调用)来更快地完成这两项工作。