先发自拍抗压!
正题
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
概念:
子序列:子序列相对于字串不要求连续, 如 [1,5,2,3,4] , 那么 1,2,3,4 为子序列,即使中间夹5,但他们依然是生序子序列。
严格递增: 严格递增即依次元素必须为递增,不包含相等,如: [1,2,3,4] 为严格递增. [1,2,2,3,4] 非严格递增
这样的需求如果使用枚举暴力破解似乎可以达到目的,但细节要求太多,而且复杂度过高,消耗性能极大,所以不作暴力破解的算法研究。
分析:
以上图为例,
一眼看去,从10开始,有:
10,101 长度为2
10,18 长度为2
9,101 长度为2
9,18 长度为2
2,5,7,101 长度为4
2,5,7,18 长度为4
2,3,7,101 长度为4
2,3,7,18 长度为4
.
.
.
等等
由上可知,我到达 101 这个元素的时候,其长度可能最大为 4。到达18这个元素时,其长度最大可能为4.那么可以记录下到达每一个元素的可能的最大序列长度,然后比较这些长度的大小,即可完成该问题
如何计算到达每个元素下的最大可能长度?
答案是:动态规划!
动态规划的基本概念:动态规划过程是每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
如何实现动态规划
创建和目标数组相同大小的数组dbList,每个元素的值为1,为什么是1呢,因为在没有计算和遍历之前,默认每个元素本身就是一个子序列,它的长度为1
通过内外循环两两比对,更改 dpList 对应数值,即修改到达该元素需要的最大长度。
动态规划图解:
动图时间有点长,看完之后应该就对动态规划有一定了解!
代码实现:
/**
* @param {number[]} nums
* @return {number}
*/
var lengthOfLIS = function (nums) {
let dp = new Array(nums.length).fill(1)
for (let i = 1; i < nums.length; i++) { // 外循环
const right = nums[i]
for (let j = 0; j < i; j++) { // 内循环
const left = nums[j]
if (left < right) {
dp[i] = Math.max(dp[i], dp[j] + 1) //记录长度
}
}
}
return Math.max(...dp) // 取得最大长度
};
console.log(lengthOfLIS([0, 1, 0, 3, 2, 3]))