【DP】最长递增子序列
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
dp = [1] * len(nums)
for i in range(1, len(nums)):
for j in range(i):
if nums[i] > nums[j]:
print(f"current num[j]:{nums[j]}, dp[i]:{dp[i]}")
dp[i] = max(dp[i], dp[j] + 1)
print(dp)
return max(dp)
这道题的本质是
我们使用一个一维数组 dp,其中 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。我们从左到右遍历数组 nums,对于每个位置 i,我们遍历其之前的所有位置 j(0 <= j < i),如果 nums[i] 大于 nums[j],则说明我们可以将 nums[i] 加在以 nums[j] 结尾的最长递增子序列的后面,形成一个更长的递增子序列。因此,我们更新 dp[i] = max(dp[i], dp[j] + 1),取其中的较大值
注意:最后返回结果用max(dp) 而不是dp[-1],需要区分结果存在最后一个元素和结果不存在最后一个元素的情况,试比较:
A 最长递增子序列
当我们使用 max(dp)
来返回最长递增子序列的长度时,我们是在找到 dp
数组中的最大值。这是因为 dp
数组中的每个元素 dp[i]
表示以 nums[i]
结尾的最长递增子序列的长度。因此,dp
数组中的最大值即为整个数组 nums
的最长递增子序列的长度。
另一方面,dp[-1]
是指 dp
数组中的最后一个元素。在这个特定的问题中,dp[-1]
可能不一定等于最长递增子序列的长度,因为我们无法保证最长递增子序列必然以 nums
数组的最后一个元素结尾。
举个例子来说明,假设 nums
是 [1, 3, 2, 4, 5]
,而 dp
数组经过计算为 [1, 2, 2, 3, 4]
。在这种情况下,最长递增子序列的长度是 4,而 dp[-1]
的值是 4。但是,如果 nums
是 [1, 2, 3, 4, 5]
,那么最长递增子序列的长度仍然是 5,但 dp[-1]
的值仍然是 4。
因此,为了正确地返回最长递增子序列的长度,我们应该使用 max(dp)
而不是 dp[-1]
,以获取 dp
数组中的最大值。
B 最大连续子数组的和
在某些特定情况下,dp[-1] 可能会用作返回值。这种情况通常出现在动态规划问题中,其中 dp 数组表示状态的转移。当 dp 数组中的最后一个元素 dp[-1] 记录的是问题的最终解时,我们可以返回 dp[-1] 作为答案。
举一个例子来说明。考虑以下问题:给定一个数组 nums,要求计算最大连续子数组的和。我们可以使用动态规划来解决这个问题,定义 dp[i] 为以 nums[i] 结尾的最大连续子数组的和。状态转移方程为 dp[i] = max(dp[i-1] + nums[i], nums[i]),即要么将 nums[i] 加入之前的子数组中,要么以 nums[i] 作为新的子数组的起点