js-challenges
js-challenges copied to clipboard
最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
参考代码如下:
/**
* @param {number[]} nums
* @return {number}
*/
var lengthOfLIS = function(nums) {
let n = nums.length, res = 0;
let f = new Array(n).fill(1)
for(let i = 0; i < n; i++)
for(let j = 0; j <=i; j++){
if(nums[j] < nums[i]){
f[i] = Math.max(f[i], f[j] + 1)
}
}
for(let i = 0; i < n; i++){
res = Math.max(f[i],res)
}
return res
};
讲解: https://www.objectkaz.cn/c69193456318.html
动态规划,dp大法
/**
* 给定一个无序的整数数组,找到其中最长上升子序列的长度。
* @param nums
* @returns
*/
const lengthOfLIS = function (nums: number[]): number {
if (nums.length === 0) return 0;
const dp = new Array<number>(nums.length).fill(1);
let maxLen = 1;
// 从第2个元素开始,遍历整个数组
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[i], dp[j] + 1);
}
}
if (dp[i] > maxLen) {
maxLen = dp[i];
}
}
return maxLen;
};
// test
console.log(lengthOfLIS([10, 9, 2, 5, 3, 7, 101, 18]));
/**
* @param {number[]} nums
* @return {number}
*/
优化查找
思路:维护一个队列,该队列保持递增。如果新的数比队尾要小,那么在队列里找到第一个比他
大的并且替换调。
var lengthOfLIS = function (nums) {
if (nums.length === 0) return 0;
let res = 0;
let queue = [], index = 0
const max = (a, b) => a > b ? a : b;
// 二分查找:查找出第一个比当前数大或者等于的数
const check = (queue, val, l, r) => {
let mid = (l + r) >> 1
if (l >= r) return r
if (queue[mid] > val) {
return check(queue, val, l, mid)
} else if (queue[mid] < val) {
return check(queue, val, mid + 1, r)
} else return mid
}
queue[0] = nums[0]
for (let i = 1; i < nums.length; i++) {
if (queue[index] < nums[i]) {
queue[++index] = nums[i]
}
else {
let t = check(queue, nums[i], 0, index);
queue[t] = nums[i]
}
res = max(res, queue.length);
}
res = max(res, queue.length);
return res
};