【DP】最长递增子序列

https://leetcode.cn/problems/longest-increasing-subsequence/?envType=study-plan-v2&envId=top-interview-150

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] 作为新的子数组的起点

posted @ 2024-04-26 14:19  peterzh6  阅读(7)  评论(0编辑  收藏  举报