Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么我的算法超时了?_Python_Dynamic Programming_Memoization - Fatal编程技术网

Python 为什么我的算法超时了?

Python 为什么我的算法超时了?,python,dynamic-programming,memoization,Python,Dynamic Programming,Memoization,下面是问题(来自Leetcode): 以下是我的解决方案: memo = {} def lis_calc(lower_bound, offset): if memo.get((lower_bound, offset), None): return memo[(lower_bound, offset)] if offset >= len(nums): return 0 if nums[offset] > lower_bound:

下面是问题(来自Leetcode):

以下是我的解决方案:

memo = {} 
def lis_calc(lower_bound, offset):
    if memo.get((lower_bound, offset), None):
        return memo[(lower_bound, offset)]
    if offset >= len(nums):
        return 0
    if nums[offset] > lower_bound:
        res = max(1 + lis_calc(nums[offset], offset + 1), lis_calc(lower_bound, offset + 1))
    else:
        res = lis_calc(lower_bound, offset + 1)

    memo[(lower_bound, offset)] = res 
    return memo[(lower_bound, offset)]
在最坏的情况下(列表已经按升序排序),我们将有NxN唯一的函数调用(每对参数有N个值)。然而,我的算法对于非常大的输入是超时的,这表明我的算法没有O(NxN)的最坏情况时间开销。我在这里做错什么了吗?似乎是DP+记忆化的简单实现。它超时的测试输入是
list(范围(12501))


我通过
lis\u calc(float('-inf'),0)
调用函数您的算法可能不是二次的,而是指数的

请看以下代码:

if nums[offset] > lower_bound:
    res = max(1 + lis_calc(nums[offset], offset + 1), lis_calc(lower_bound, offset + 1))
在每一步,在最坏的情况下,你打两个电话。这两个电话中的每一个,在最坏的情况下,都会打两个电话。这四个电话中的每一个都会打两个电话,以此类推

如果两件事中有一件是真的,那么您的算法仍然可以是多项式的:

  • 如果这些新呼叫中至少有一半被缓存,或者
  • 如果保证最坏情况将在最坏
    log N
    步骤中减少到下限情况(变为线性)
但据我所知,这两个都不是真的。所以,在最坏的情况下,您的算法需要
O(2**N)
步骤。这就是为什么它太慢了


或者……也许这不是真的,也许这只是需要一个额外的常数因子的二次时间,2500正好接近他们期望您的代码可以轻松工作的边缘,而您只是没有完全通过


每次加倍调用时,您不会缓存其中的一半,但应该缓存其中的一半
N-1
。因此,如果一切正常,你的总步骤应该是
N*(N+1)+1
,但如果你的步骤稍有错误,则可能会偏离4倍……尽管确实如此,我认为,如果在他们测试的最大数字上,常数因子4足以产生差异,那么这不是一个很好的测试。

在每一步中,你都要进行两次递归调用,除非你低于下限。它们有不同的参数,所以备忘录缓存不会有帮助。这两个电话中的每一个都会打两个电话,每一个都会打两个电话,依此类推。因此,除非你有证据证明在到达下限之前只能记录N个步骤,而不是N个步骤,否则你的代码是
O(2**N)
,而不是
O(N**2)
。事实上,现在我想起来了……你没有在每次加倍调用时缓存一半的调用,但是您应该缓存
N
N-1
的一半,因此,时间应该是
N*(N+1)+1
,这毕竟是二次的。所以也许有一些小瑕疵可以修复?要测试这一点,请尝试添加呼叫数的计数。它是以
N*(N+1)+1为界,还是简单地说,只是
2*N**2
?并统计缓存命中数;它是否接近于
N**2/2
?如果答案是肯定和肯定的,那么我的答案是错误的,但这很好;我可以删除它。:)请注意,您的代码正在执行显式递归。这与动态规划不同。DP通常使用数组来存储结果,这样您就不必每次需要时都重新计算它们。您应该阅读一些关于如何调试代码的提示。您可以使用这些提示来验证您的算法是否正确,或者找到不正确的地方。
if nums[offset] > lower_bound:
    res = max(1 + lis_calc(nums[offset], offset + 1), lis_calc(lower_bound, offset + 1))