最长递增子序列
已解答
中等
相关标签
相关企业
给你一个整数数组 nums
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
-
1 <= nums.length <= 2500 -
-104 <= nums[i] <= 104
进阶:
-
你能将算法的时间复杂度降低到
O(n log(n))吗?
面试中遇到过这道题?
1/5
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
size = len(nums)
dp = [1 for _ in range(size)]
for i in range(size):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
方法二:动态规划 首先考虑题目问什么,就把什么定义成状态。题目问最长上升子序列的长度,其实可以把「子序列的长度」定义成状态,但是发现「状态转移」不好做。
基于「动态规划」的状态设计需要满足「无后效性」的设计思想,可以将状态定义为「以 nums[i] 结尾 的「上升子序列」的长度」。
「无后效性」的设计思想:让不确定的因素确定下来,以保证求解的过程形成一个逻辑上的有向无环图。这题不确定的因素是某个元素是否被选中,而我们设计状态的时候,让 nums[i] 必需被选中,这一点是「让不确定的因素确定下来」,也是我们这样设计状态的原因。
-
定义状态:
dp[i] 表示:以 nums[i] 结尾 的「上升子序列」的长度。注意:这个定义中 nums[i] 必须被选取,且必须是这个子序列的最后一个元素;
-
状态转移方程:
如果一个较大的数接在较小的数后面,就会形成一个更长的子序列。只要 nums[i] 严格大于在它位置之前的某个数,那么 nums[i] 就可以接在这个数后面形成一个更长的上升子序列。
dp[i]= 0≤j<i,nums[j]<nums[i] max
dp[j]+1
-
初始化:
dp[i] = 1,1 个字符显然是长度为 1 的上升子序列。
-
输出: 不能返回最后一个状态值,最后一个状态值只表示以 nums[len - 1] 结尾的「上升子序列」的长度,状态数组 dp 的最大值才是题目要求的结果。
1≤i≤N max
dp[i]
-
空间优化:
遍历到一个新数的时候,之前所有的状态值都得保留,因此无法优化空间。
可以看下面的例子理解「动态规划」的执行流程。由于幻灯片上的文字比较多,可以先让幻灯片动起来,从整体把握思想。
作者:liweiwei1419 链接:https://leetcode.cn/problems/longest-increasing-subsequence/solutions/7196/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/ 来源:力扣(LeetCode)

浙公网安备 33010602011771号