「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」
给你一个整数数组 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
动态规划
定义 为考虑前 i 个元素,以第 i 个数字结尾的最长上升子序列的长度,注意 必须被选取。
我们从小到大计算 dp\textit{dp}dp 数组的值,在计算 之前,我们已经计算出 的值,则状态转移方程为:
即考虑往 中最长的上升子序列后面再加一个 。由于 代表 中以 结尾的最长上升子序列,所以如果能从 这个状态转移过来,那么 必然要大于 ,才能将 放在 后面以形成更长的上升子序列。
最后,整个数组的最长上升子序列即所有 中的最大值。
/**
* @param {number[]} nums
* @return {number}
*/
var lengthOfLIS = function (nums) {
const dp = new Array(nums.length).fill(1);
for (let i = 0; i < nums.length; i++) {
// i与i前面的元素比较
for (let j = 0; j < i; j++) {
// 找比i小的元素,找到一个,就让当前序列的最长子序列长度加1
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// 找出最大的子序列
return Math.max(...dp);
};
复杂度分析
-
时间复杂度:,其中 n 为数组 nums 的长度。动态规划的状态数为 n,计算状态 dp[i] 时,需要 O(n) 的时间遍历 dp[0…i−1] 的所有状态,所以总时间复杂度为 O(n^2)。
-
空间复杂度:O(n),需要额外使用长度为 n 的 dp 数组。