这是力扣第 300 题:
随着 vue3 的流行,最长递增子序列这道算法题火遍全网,让前端开发人员也接触到了动态规划这个算法。题目如下:
给你一个整数数组
nums,找到其中最长递增子序列的长度。
这种类型的题目,一般都是利用动态规划来做,难点在于找到状态转移方程,即 dp[i] 是什么,它跟 dp[i-1] 之间到底是什么关系?
那就不解释了,只要记住:
dp[i]表示以nums[i]结尾的最长递增子序列的长度
很明显,dp 数组的初始值都是 1,因为 [nums[i]] 是保底的,所以代码如下:
function lengthOfLIS(nums) {
const length = nums.length // 获取数组长度
const dp = Array.from({length}, () => 1) // 初始化 dp 数组,长度与 nums 相同,值全是 1
for (let i = 0; i < length; i++) { // 从左到右遍历
const vi = nums[i] // 取 nums[i] 的值
for (let j = 0; j < i; j++) { // 从 0 遍历到 i
const vj = nums[j] // 取 nums[j] 的值
if (vi > vj) {
dp[i] = Math.max(dp[i], 1 + dp[j]) // 如果 i 位的值大于 j 位的值,则最长递增子序列可以在 j 的基础上加 1
}
}
}
return Math.max(...dp) // 取 dp 数组中最大的值
}
所以状态转移方程就是:
当
nums[i] > nums[j]的时候,dp[i] = Math.max(dp[i], 1 + dp[j])
记住了吗?
这一题其实还有一个二维场景的变形,即力扣第 354 题俄罗斯套娃信封:
给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。请计算最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
这道题只要排序一下就跟求最长递增子序列一样了:
function maxEnvelopes(envelopes) {
envelopes.sort(([a1, a2], [b1, b2]) => {
if (a1 > b1) return 1
else if (a1 < b1) return -1
else return b2 - a2
})
const arr = envelopes.map(items => items[1])
// 求 arr 的最长递增子序列
return lengthOfLIS(arr)
}
也就是说只要按照宽度为主、高度为辅(或者高度为主、宽度为辅)从小到大排好序,然后求高度(宽度)数组的最长递增子序列即可。
本文正在参与「掘金 3 月闯关活动」,点击查看活动详情。