开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情
300. 最长递增子序列 题目描述:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。
子序列是字符元素不一定连续,但相对位置一致的序列。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
| 示例1 | 示例2 | 示例3 |
|---|---|---|
输入:nums = [10,9,2,5,3,7,101,18] 输出: 解释:最长递增子序列是 [2,3,7,101],因此长度为 。 | 输入:nums = [0,1,0,3,2,3] 输出: | 输入:nums = [7,7,7,7,7,7,7] 输出: |
中规中矩的动态规划
本题与 # 674. 最长连续递增序列 仅差 “连续” 二字,但是整体的解题思路不变。
1、确定 dp 状态数组
依然定义 是以 结尾的严格递增子序列的长度,其中 。
2、确定 dp 状态方程
既然子序列可以不连续,当我们遍历到 时,不能仅仅判断 与 ,还额外需要另外一维状态,即 ,其中 。
-
当 时,符合严格递增, 此时存在 ;
-
当 时,直接忽略即可。
NOTE: 每次遍历 时需要对 取最大值,即
3、确定 dp 初始状态
初始化的每个元素为 (非严格增序数列的最长递增序列为 );
4、确定遍历顺序
-
外层循环从 遍历到 ;
-
内层循环从 遍历到 。
5、确定最终返回值
回归到 定义中, 仅代表以 结尾的最长子序列的长度,并不是全局最长子序列的长度,应该从 数组中选择最大值,即 。
6、代码示例
/**
* 空间复杂度 O(n)
* 时间复杂度 O(n^2)
*/
function lengthOfLIS(nums: number[]): number {
const n = nums.length;
const dp = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return Math.max(...dp);
};
/**
* 空间复杂度 O(n)
* 时间复杂度 O(n^2)
*/
function lengthOfLIS(nums: number[]): number {
const n = nums.length;
const dp = new Array(n).fill(1);
let ans = 1;
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
ans = Math.max(ans, dp[i])
}
return ans;
};