携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
题目描述
题目分析
由题目分析可知,一个非空数组的最长递增子序列的最小值一定是1(即使该数组是一个递减数组),假设一个数组的长度为k,其最长递增子序列长度为len,再像数组后面加入一个数字,那么长度为k+1的数组的最长递增子序列,一定可以由长度为k的数组推导出来,可能为len(加入的数字比递增子序列的最大值小),可能为len+1(加入的数字比递增子序列的最大值大),可由动态规划解决。
状态转移分析
1.dp[i]定义
dp[i] 表示数组nums以nums[i]结尾的子数组的最长上升子序列的长度
2.状态转移公式
如果nums[i] > nums[j]:
位置i的最长上升子序列等于(j从0到i-1各个位置的最长上升子序列+1) 的最大值
dp[i] = Math.max(dp[i],dp[j]+1) // 求从0-j-1各个位置的最长递增子序列+1取最大值并循环更新dp[i
如果nums[i]<= nums[j]
说明加入nums[i]之后,最长递增子序列的长度不变
3.初始值
一个非空数组的最长递增子序列的最小值一定是1 dp = Array(nums.length).fill(1)
4.遍历顺序
显而易见应该从前往后遍历
代码实现
var lengthOfLIS = function(nums) {
if(nums.length<=1) return nums.length
let result = 0;
const dp = Array(nums.length).fill(1)
for(let i = 1;i<nums.length;i++){
for(let j = 0;j<i;j++ ){
if(nums[i]>nums[j]) {
dp[i] = Math.max(dp[i],dp[j]+1)
}
}
if(dp[i] > result) result = dp[i]
console.log("i------------", i, dp, result);
}
return result
};
以数组 [2,5,3,5,1] 为例
初始化dp = [1,1,1,1,1]
result = 0;
第一轮外层循环:
i = 1:
内层寻循环:
j = 0; 5>2 => dp[i] = Math.max(1,1+1) = 2
dp = [1,2,1,1,1]
result = max(result,dp[1]) = 2;
循环结束
第二层外层循环
i = 2:
内层循环:
j = 0; 3>2 => dp[i] = max(1,1+1) => 2
j = 1; 3<5 => 不处理
dp = [1,2,2,1,1]
result = max(result,dp[2]) = 2;
循环结束
第三册外层循环:
i = 3:
内层循环:
j = 0: 5>2 => dp[i] = max(1,1+1) => 2
j = 1 5=5 => 不处理
j = 2 5>3 => dp[i] = max(1,2+1) => 3
循环结束
dp = [1,2,2,3,1]
result = max(result,dp[3]) = 3;
第四层外层循环:
i = 4:
内层循环:
j = 0; 1 < 2 => 不处理
j = 1; 1 < 5 => 不处理
j = 2; 1 < 3 => 不处理
j = 3; 1 < 5 => 不处理
dp = [1,2,2,3,1]
result = max(result,dp[4]) = 3;
运行截图
以上为个人理解,欢迎各位大佬指正。