我试图理解为什么使用lru_cache
来解决这个问题会产生更慢的代码性能。
问题本质上是返回所有加起来达到某个目标的组合。
我正在使用lru_cache
装饰器进行记忆(docs),这是我的解决方案:
from functools import lru_cache
def combinationSum(candidates, target):
return dfs(tuple(candidates), 0, target)
@lru_cache(maxsize=None)
def dfs(candidates, i, target):
if target < 0:
return []
if target == 0:
return [[]]
if i == len(candidates):
return []
final_results = []
for j in range(i, len(candidates)):
results = dfs(candidates, j, target - candidates[j])
for x in results:
final_results.append([candidates[j]] + x)
return final_results
似乎当lru_cache
装饰器被注释掉时,这个算法的运行速度几乎提高了 50%。这似乎有点违反直觉,因为我认为应该降低解决方案的时间复杂度,即使增加了从记忆中检索结果的函数调用开销。
对于记忆的解决方案,我认为时间复杂度应该是数组的长度在O(n^2*k*2^n)
哪里,并且是从到范围内的所有数字。n
k
0
target
这是我的分析(需要一点帮助验证):
time complexity
= possible states for memoization x work done at each step
= (n * k) * (n * maximum size of results)
= n * k * n * 2^n
在如何分析递归解决方案的时间复杂度方面,我也缺少一些知识空白,我可以为此提供一些帮助!
编辑:
我range(1, 10000)
用作测试输入,以下是基准:
# with lru_cache
$ time python3 combination_sum.py
CacheInfo(hits=59984, misses=49996, maxsize=None, currsize=49996)
real 0m4.031s
user 0m3.996s
sys 0m0.024s
# without lru_cache
$ time python3 combination_sum.py
real 0m0.073s
user 0m0.060s
sys 0m0.010s