问题出在这里(来自Leetcode):
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Note:
There may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
这是我的解决方法:
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个唯一的函数调用(成对的每个arg N个值)。但是,我的算法正在为非常大的输入而超时,这表明我的算法没有最坏情况下的O(NxN)时间成本。我在这里做错了什么吗?似乎是DP +备忘的直接实现。超时的测试输入为list(range(1,2501))
我通过lis_calc(float('-inf'), 0)
答案 0 :(得分:1)
您的算法可能不是平方的,而是指数的。
看下面的代码:
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足以使结果有所不同。