原题链接
解题思路:
状态定义:
- 的值代表
nums
前 个数字的最长子序列长度,或者说以第i个数字结尾的最长上升子序列长度
- 的值代表
转移方程: 设 ,考虑每轮计算新 时,遍历 列表区间,做以下判断:
- 当 时: 说明 可以接在 之后(此题要求严格递增),此情况下最长上升子序列长度为 ;
- 当 时: 说明 无法接在 之后,此情况上升子序列不成立,跳过。
- 上述所有 1情况 下计算出的 的最大值,为直到 的最长上升子序列长度(即 )。实现方式为遍历 时,每轮执行 。
- 转移方程:
dp[i] = max(dp[i], dp[j] + 1) for j in [0, i)
。
初始状态:
- 所有元素置 ,含义是每个元素都至少可以单独成为子序列,此时长度都为 。
返回值:
- 返回 列表最大值,即可得到全局最长上升子序列长度。
复杂度分析:
- 时间复杂度 : 遍历计算 列表需 ,计算每个 需 。
- 空间复杂度 : 列表占用线性大小额外空间。
代码:
typescript
function lengthOfLIS(nums: number[]): number {
if(!nums || !nums.length) {
return 0;
}
// dp[i] 代表以第i个数字结尾的最长上升子序列长度
// 状态转移: dp[i] = Max(dp[j]) + 1 (0 <= j <= i)
const dp = new Array(nums.length).fill(1);
for(let i = 1; i < nums.length; i++) {
for(let j = 0; j < i; j++) {
if(nums[j] < nums[i]) {
// 可以接在若干数字后面 但只选能使子序列长度最大的那个
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
}
return Math.max(...dp);
};