算法篇——动态规划最终篇 (js版)

动态规划做题顺序:

  • 确定 dpi 的意义
  • 确定递推公式
  • 初始化 dpi
  • 确定遍历顺序
  • 举例分析
300. 最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,3,6,2,7 是数组 0,3,1,6,2,2,7 的子序列。

链接:力扣

解题思路:

本题主要考虑 元素的递增 ,因此确定 递推公式 时,也要考虑 当前遍历后的子序列的尾元素 和 即将要遍历的元素 谁大,从而确定 递归序列的尾元素 是谁。

所以 dpi 就是表示 当前遍历后的子序列的长度。并且可以确定递推公式:

dpi = Math.max(dpi, dpj + 1) && numsi > numsj

这里的比较是针对取最大的 dpj 的子序列长度,不是将 dpi 和 dpj 进行比较,也可以理解成这样:

dpi = Math.max(dpj) + 1 && numsi > numsj && 0 <= j < i

再求解 Math.max(dpi) 即可

初始化长度为1,因为长度至少是1。

javascript 复制代码
var lengthOfLIS = function(nums) {
    if(nums.length == 1) return 1
    // 初始化都为1
    let dp = Array(nums.length).fill(1)
    // 递增子序列的长度
    let res = 1
    for(let i = 1; i < nums.length; i++) {
        for(let j = 0; j < i; j++) {
            // 获取最大的 dp[j]
            if(nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1)
        }
        // 得到最长子序列长度
        res = Math.max(dp[i], res)
    }
    return res
}
674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 numsi < numsi + 1 ,那么子序列 nums\[l, numsl + 1, ..., numsr - 1, numsr] 就是连续递增子序列

链接:力扣

解题思路:

本题与上一题的不同之处在于,这道题强调 "连续",也就是说不比较 numsj 与 numsi(j 从0遍历到 i),而是比较 numsi 与 numsi - 1,也就无需双层循环。连续递增的子序列长度最小是1,所以初始化是1。递推公式是:

dpi = dpi - 1 + 1 && numsi > numsi - 1

javascript 复制代码
var findLengthOfLCIS = function(nums) {
    if(nums.length == 1) return 1
    // 初始化都为1
    let dp = Array(nums.length).fill(1)
    // 递增子序列的长度
    let res = 1
    for(var i = 1; i < nums.length; i++) {
        if(nums[i] > nums[i-1]) dp[i] = dp[i-1] + 1
        if (dp[i] > res) res = dp[i]
    }
    return res
}

718. 最长重复子数组

给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度。

链接:力扣

解题思路:

本题是要在连续最长子序列基础上,找到两个数组中的公共序列,因此,确定 dpij 是以 i - 1结尾的子序列1,和以 j - 1结尾的子序列2,最长重复子序列长度为 dpij。确定递推公式是:

dpij = dpi - 1j - 1 + 1 && nums1i - 1 == nums2j - 1

关于初始化:dpi0 和dp0j 在整个递推过程中没有实际意义,所以dpi0 和dp0j初始化为0。(这里需要初始化,方便递推)这里的遍历顺序可以先1后2或者先2后1都可以。

javascript 复制代码
var findLength = function(nums1, nums2) {
    const len1 = nums1.length, len2 = nums2.length
    // dp数组初始化,都初始化为0
    const dp = Array.from({ length: len1 + 1 }, () => Array(len2 + 1).fill(0))
    // 初始化最大长度为0
    let res = 0
    for(let i = 1; i <= len1; i++) {
        for(let j = 1; j <= len2; j++) {
            if(nums1[i - 1] == nums2[j - 1]) 
                dp[i][j] = dp[i - 1][j - 1] + 1
            res = Math.max(res, dp[i][j])
        }
    }
    return res
}
相关推荐
Delightrs27 分钟前
Rust LeetCode238 算法题解
开发语言·算法·rust
云上工程笔记1 小时前
SRT字幕一键转手绘动画:srt-whiteboard-animation的复刻实录
大数据·开发语言·javascript·人工智能·机器学习
自信150413057591 小时前
重生之从0开始学习c++之——vector-中篇
c++·学习·算法
FungLeo1 小时前
成为全栈·Vue管理后台篇·<scriptsetup>:把页面拆成可读、可测的 Vue 组件
前端·javascript·vue.js·typescript·前端组件化·composition api·vue sfc
GoAI12 小时前
DeepSeek Harness Memory (一)主流记忆插件总结
后端·算法·面试
Pniubi13 小时前
力扣54.螺旋矩阵
算法·leetcode·矩阵
清晨Coding14 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
kyriewen14 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
choumou_M15 小时前
算法_1:由浅入深学习快速排序QuickSort
学习·算法·排序算法