「LeetCode300」最长递增子序列|刷题打卡

152 阅读2分钟

这是力扣第 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 月闯关活动」,点击查看活动详情