leetcode300--最长上升子序列LIS

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

法1:动态规划

参考:动态规划 + 贪心算法(二分法)(Python 代码、Java 代码)

定义状态:dp[i] 表示以第 i 个数字为结尾的最长上升子序列的长度。即在 [0, ..., i] 的范围内,选择 以数字 nums[i] 结尾 可以获得的最长上升子序列的长度。注意:以第 i 个数字为结尾,即 要求 nums[i] 必须被选取。反正一个子序列一定会以一个数字结尾,那我就将状态这么定义,这一点是常见的。

状态转移方程:遍历到索引是 i 的数的时候,我们应该把索引是 [0, ... ,i - 1] 的 dp 都看一遍,如果当前的数 nums[i] 严格大于之前的某个数,那么 nums[i] 就可以接在这个数后面形成一个更长的上升子序列。把前面的 i 个数都看了,dp[i] 就是它们的最大值加 1。即比当前数要小的那些里头,找最大的,然后加 1 。

总结一下,状态转移方程是:

dp[i] = max{dp[i], dp[j]+1}

最后不要忘记,扫描一遍这个 dp 数组,其中最大值的就是题目要求的最长上升子序列的长度。

复杂度分析:

时间复杂度:O(N^2)因为有两个 for 循环,每个 for 循环的时间复杂度都是线性的。
空间复杂度:O(N),要开和数组等长的状态数组,最后要再看一遍状态数组的最大值。

class Solution:
    def lengthOfLIS(self, nums):
        length = len(nums)
        if length <= 1:
            return length
        
        dp = [1] * length
        for i in range(1, length):
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)   # 最后要全部看一遍,取最大值

#dp[i]表示以nums[i]为结尾时的最大长度。
#当nums[i]比前面的元素大时,就可以将nums[i]放入前面找到的最长递增子序列的后面构成更长的递增子序列。
#因为前面满足nums[i]>nums[j]的j很多(j=0,1,...,i-1),所以需要更新dp[i],所以才会有max(dp[i],dp[j]+1)

猜你喜欢

转载自blog.csdn.net/yzy__zju/article/details/95622094
今日推荐