【发布时间】:2021-08-08 02:02:22
【问题描述】:
我是 DP 的初学者,我正在尝试解决一个 Leetcode 问题 - Maximum Subarray:给定一个整数数组 nums,找到总和最大的连续子数组(至少包含一个数字)并返回它的总和.我知道这个问题已经有很多 DP 解决方案。但是我想自己写一个DP解决方案,我在网上搜索了一些关于DP的介绍。这是我正在使用的具体参考:https://stackoverflow.com/a/13538715/9982458。根据这个答案,DP的运行时间是O(n)。为什么我的代码收到 Time Limit Exceeded 错误?任何 cmets 将不胜感激!谢谢!
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dp = {} # dp[i] means maxSubArray for nums[0:i] which must has A[i-1] as the end element.
m = nums[0]
def DP(nums):
if len(nums) in dp:
return dp[len(nums)]
else:
if len(nums) == 1:
f = nums[-1]
else:
temp = DP(nums[0:-1])
if temp > 0:
f = temp + nums[-1]
else:
f = nums[-1]
dp[len(nums)] = f
return f
DP(nums)
for i in range(1, len(nums)):
m = max(m, dp[i])
return m
【问题讨论】:
-
动态规划方法的运行时间为O(n)是正确的。但是,您的实现是 O(n^2)。特别是你应该注意
nums[0:-1]不是一个常数时间的操作,所以你对DP的调用是O(n)。这可以通过多种方式解决。 -
你能说更多关于
nums[0:-1]不是常数时间吗?我不太明白我的nums[0:-1]和stackoverflow.com/a/13538715/9982458 中的fib(n-1) + fib(n-2)之间的区别。为什么这是一个恒定的时间? -
您的 DP 解决方案是自上而下的,但
nums[0:-1]需要线性时间来切片阵列。尝试使用自下而上的 DP 解决方案 -
这里的代码太多了。这最多应该是 5-6 行——如果你写的不止这些,可能会备份并重新评估。不需要任何切片。
nums[0:-1]是列表的一个几乎完整的切片,逐个元素地复制它。如果列表有一百万个元素,则需要与此成正比的时间。 O(1) 意味着您可以在复制空列表的同时复制任意大的列表——显然是错误的。这与fib(n-1) + fib(n-2)无关——如果没有更多上下文(没有记忆,O(2^n),有备忘录,O(n)),尚不清楚 TC 会是什么。 -
nums[0:-1]copiesnums,所以它所花费的时间与它的长度成正比。如果你想在 Python 中为这个问题实现线性时间自上而下的 DP(我建议将其作为学习练习,因为我见过的所有实现都是自下而上的!),我认为你需要制作内部DP()函数是一个不将nums作为参数的闭包,而是依赖于它在其父函数范围内查看现有局部变量的能力。这个函数应该只接受一个整数endIndex参数,可以在恒定时间内复制。
标签: algorithm time-complexity dynamic-programming divide-and-conquer