「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题意描述
给你一个整数数组 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
分析
这应该是非常非常经典的题型了吧,这类题型一般有两种做法,一种是DP也就是动态规划,另一种做法就是二分查找法。
解法一:DP
思路:我们去维护一个额外的数组,该数组存放最长递增序列,如果要插入的数据无法构成最大递增子序列,所以不能插入,但后面可能有更长的序列,所以在保持原数组仍为最大递增序列的情况下把4放进去,也就是把3更新为4,为后面可能出现的最大递增序列做准备。
var lengthOfLIS = function(nums) {
const dp = new Array(nums.length)
dp[0] = 1
// 步骤1:计算dp[i]的对应长度
for(let i = 1; i < dp.length; i++) {
// 寻找前面小于nums[i]的最大dp值
let j = 0
let belowMaxDP = 0
while (j < i) {
if (nums[j] < nums[i] && dp[j] > belowMaxDP) {
belowMaxDP = dp[j]
}
j++
}
dp[i] = belowMaxDP + 1
}
let max = 1
let i = 0
while (i < dp.length) {
if (dp[i] > max) {
max = dp[i]
}
i++
}
return max
};
解法2:DP+二分
思路:在之前的思路上加上二分,提高效率。
var lengthOfLIS = function(nums) {
const dp = new Array(nums.length).fill(0)
let len = 0
for(let i = 0;i < nums.length;i++) {
let ind = binarySearch(dp, 0, len, nums[i])
if(ind < 0) ind = -ind
dp[ind] = nums[i]
if(ind === len) len++
}
return len
};
function binarySearch(arr, from ,to, target){
if(to === 0) return -0
if(target < arr[from]) return -from
if(target > arr[to - 1]) return -to
let l = from
let r = to
while(l < r) {
const mid = Math.floor((l + r) / 2)
if(target > arr[mid]) {
l = mid + 1
} else if(target < arr[mid]) {
r = mid
} else {
l = mid
r = mid
}
}
return arr[l] === target ? l : -l
}
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤