代码随想录算法训练营day52 | 动态规划之子序列 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

news2024/11/25 7:42:10

day52

      • 300.最长递增子序列
        • 1.dp[i]的定义
        • 2.状态转移方程
        • 3.dp[i]的初始化
        • 4.确定遍历顺序
        • 5.举例推导dp数组
      • 674. 最长连续递增序列
        • 1.确定dp数组(dp table)以及下标的含义
        • 2.确定递推公式
        • 3.dp数组如何初始化
        • 4.确定遍历顺序
        • 5.举例推导dp数组
      • 718. 最长重复子数组
        • 1.确定dp数组(dp table)以及下标的含义
        • 2.确定递推公式
        • 3.dp数组如何初始化
        • 4.确定遍历顺序
        • 5.举例推导dp数组

300.最长递增子序列

题目链接
解题思路: 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。

接下来,我们依然用动规五部曲来详细分析一波:

1.dp[i]的定义

dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

为什么一定表示 “以nums[i]结尾的最长递增子序” ,因为我们在做递增比较的时候,如果比较 nums[j]nums[i] 的大小,那么两个递增子序列一定分别以nums[j]为结尾 和 nums[i]为结尾, 要不然这个比较就没有意义了,不是尾部元素的比较那么 如何算递增呢。

2.状态转移方程

位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。

所以:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);

注意这里不是要dp[i]dp[j] + 1进行比较,而是我们要取dp[j] + 1的最大值。

3.dp[i]的初始化

每一个i,对应的dp[i](即最长递增子序列)起始大小至少都是1.

4.确定遍历顺序

dp[i] 是有0i-1各个位置的最长递增子序列 推导而来,那么遍历i一定是从前向后遍历。

j其实就是遍历0i-1,那么是从前到后,还是从后到前遍历都无所谓,只要吧 0 到 i-1 的元素都遍历了就行了。 所以默认习惯 从前向后遍历。

遍历i的循环在外层,遍历j则在内层,代码如下:

for (int i = 1; i < nums.size(); i++) {
    for (int j = 0; j < i; j++) {
        if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
    }
    if (dp[i] > result) result = dp[i]; // 取长的子序列
}

5.举例推导dp数组

输入:[0,1,0,3,2],dp数组的变化如下:
在这里插入图片描述
以上五部分析完毕,C++代码如下:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        vector<int> dp(nums.size(), 1);
        int result = 0;
        for (int i = 1; i < nums.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
            }
            if (dp[i] > result) result = dp[i]; // 取长的子序列
        }
        return result;
    }
};

674. 最长连续递增序列

题目链接
解题思路: 本题和上一题最大的区别在于**“连续”**。本题要求的是最长连续递增序列

动规五部曲分析如下:

1.确定dp数组(dp table)以及下标的含义

dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。

注意这里的定义,一定是以下标i为结尾,并不是说一定以下标0为起始位置。

2.确定递推公式

如果 nums[i] > nums[i - 1],那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 + 1 。

即:dp[i] = dp[i - 1] + 1;

因为本题要求连续递增子序列,所以就只要比较nums[i]nums[i - 1],而不用去比较nums[j]nums[i] (j是在0到i之间遍历)。

既然不用j了,那么也不用两层for循环,本题一层for循环就行,比较nums[i]nums[i - 1]

这里大家要好好体会一下!

3.dp数组如何初始化

以下标i为结尾的连续递增的子序列长度最少也应该是1,即就是nums[i]这一个元素。

所以dp[i]应该初始1;

4.确定遍历顺序

从递推公式上可以看出, dp[i + 1]依赖dp[i],所以一定是从前向后遍历。

本文在确定递推公式的时候也说明了为什么本题只需要一层for循环,代码如下:

for (int i = 1; i < nums.size(); i++) {
    if (nums[i] > nums[i - 1]) { // 连续记录
        dp[i] = dp[i - 1] + 1;
    }
}

5.举例推导dp数组

已输入nums = [1,3,5,4,7]为例,dp数组状态如下:
在这里插入图片描述注意这里要取dp[i]里的最大值,所以dp[2]才是结果!

以上分析完毕,C++代码如下:

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        int result = 1;
        vector<int> dp(nums.size() ,1);
        for (int i = 1; i < nums.size(); i++) {
            if (nums[i] > nums[i - 1]) { // 连续记录
                dp[i] = dp[i - 1] + 1;
            }
            if (dp[i] > result) result = dp[i];
        }
        return result;
    }
};

718. 最长重复子数组

题目链接
解题思路:
本题其实是动规解决的经典题目,我们只要想到 用二维数组可以记录两个字符串的所有比较情况,这样就比较好推 递推公式了。
动规五部曲分析如下:

1.确定dp数组(dp table)以及下标的含义

dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。 (特别注意: “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 )

此时细心的同学应该发现,那dp[0][0]是什么含义呢?总不能是以下标-1为结尾的A数组吧。

其实dp[i][j]的定义也就决定着,我们在遍历dp[i][j]的时候i 和 j都要从1开始。

那有同学问了,我就定义dp[i][j]为 以下标i为结尾的A,和以下标j 为结尾的B,最长重复子数组长度。不行么?

行倒是行! 但实现起来就麻烦一点,需要单独处理初始化部分,在本题解下面的拓展内容里,我给出了 第二种 dp数组的定义方式所对应的代码和讲解,大家比较一下就了解了。

2.确定递推公式

根据dp[i][j]的定义,dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。

即当A[i - 1]B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;

根据递推公式可以看出,遍历i 和 j 要从1开始!

3.dp数组如何初始化

根据dp[i][j]的定义,dp[i][0]dp[0][j]其实都是没有意义的!

dp[i][0]dp[0][j]要初始值,因为 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1;

所以dp[i][0]dp[0][j]初始化为0。

举个例子A[0]如果和B[0]相同的话,dp[1][1] = dp[0][0] + 1,只有dp[0][0]初始为0,正好符合递推公式逐步累加起来。

4.确定遍历顺序

外层for循环遍历A,内层for循环遍历B(外层for循环遍历B,内层for循环遍历A 也可)。

同时题目要求长度最长的子数组的长度。所以在遍历的时候顺便把dp[i][j]的最大值记录下来。

代码如下:

for (int i = 1; i <= nums1.size(); i++) {
    for (int j = 1; j <= nums2.size(); j++) {
        if (nums1[i - 1] == nums2[j - 1]) {
            dp[i][j] = dp[i - 1][j - 1] + 1;
        }
        if (dp[i][j] > result) result = dp[i][j];
    }
}

5.举例推导dp数组

拿示例1中,A: [1,2,3,2,1],B: [3,2,1,4,7]为例,画一个dp数组的状态变化,如下:

在这里插入图片描述
以上五部曲分析完毕,C++代码如下

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
        int result = 0;
        for (int i = 1; i <= nums1.size(); i++) {
            for (int j = 1; j <= nums2.size(); j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                if (dp[i][j] > result) result = dp[i][j];
            }
        }
        return result;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/393909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux驱动交叉编译把驱动文件放入开发板,以及printk函数打印级别

上一篇介绍了一个最简单的驱动程序和驱动程序大体结构&#xff0c;但那还是用本地编译只能在Ubuntu上运行&#xff0c;我们该怎么编译一个能加载到开发板上呢&#xff0c;就需要交叉编译&#xff0c;交叉编译通常都是在嵌入式开发中使用到的。 交叉编译 理解交叉编译前先了解…

TypeScirpt 入门与实战 学习笔记

文章目录求一键三连前言了解TS的前世今生基本实现数据类型枚举类型 enum&#xff08;用的少&#xff09;顶端类型&#xff08;通用类型&#xff09;anyunknown对比never数组只读 &#xff1a;readonly元组 类型objectObject和Object&#xff08;&#xff09;区分命名空间&#…

论文阅读 :Masked Autoencoders As Spatiotemporal Learners

NeurIPS2022——Masked Autoencoders As Spatiotemporal Learners Keywords&#xff1a; Videos&#xff1b;object detection&#xff1b; 文章目录NeurIPS2022——Masked Autoencoders As Spatiotemporal Learners研究动机本文贡献Introduction & Related work整体架构&…

redis进阶:mysql,redis双写一致性,数据库更新后再删除缓存就够了吗?

0. 引言 最近线上的一个状态修改功能出现了问题&#xff0c;一开始是运营找了过来&#xff0c;运营告知某条数据的状态已经开启了的&#xff0c;但是实际使用起来还是没有生效&#xff0c;于是拿到这个问题后&#xff0c;首先就去数据库查了这条数据&#xff0c;发现确实如他所…

深入了解字典树

字典树&#xff08;Trie&#xff09; 目录字典树&#xff08;Trie&#xff09;一、问题引入二、字典树介绍3、字典树的实现4、存储与查询一、问题引入 现有长度为n的字符串数组&#xff0c;[“go”&#xff0c;“goog”&#xff0c;“google”&#xff0c;“golang”&#xff0…

【数据结构入门】-链表之双向循环链表

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【数据结构初阶&#xff08;C实现&#xff09;】 文章目录链表初始化打印链表尾插尾删新建一个节点头插头删查找在pos之前插入*删除pos位…

CSS中的伪元素和伪类

一直被伪类和伪元素所迷惑&#xff0c;以为是同一个属性名称&#xff0c;根据CSS动画&#xff0c;索性开始研究a:hover:after&#xff0c;a.hover:after的用法。 伪元素 是HTML中并不存在的元素&#xff0c;用于将特殊的效果添加到某些选择器。 对伪元素的描述 伪元素有两…

【Verilog】握手信号实现跨时钟域数据传输-handshake

文章目录handshake握手电路使用握手信号实现跨时钟域数据传输接口信号图题目描述解题思路代码设计数据发送模块data_driver数据接收模块data_receivertestbench波形handshake握手电路 跨时钟域处理是个很庞大并且在设计中很常出现的问题握手(handshake)是用来处理信号跨时钟域…

数字化引领乡村振兴,VR全景助力数字乡村建设

一、数字乡村建设加速经济发展随着数字化建设的推进&#xff0c;数字化农业产业正在成为农业产业发展的主导力量&#xff0c;因此数字化技术赋予农业产业竞争力的能力不可小觑。数字化乡村建设背景下&#xff0c;数字化信息技术将全面改造升级农村产业&#xff0c;从农业、养殖…

new set数组对象去重失败

我们知道Set是JS的一个种新的数据结构&#xff0c;和数组类似&#xff0c;和数组不同的是它可以去重&#xff0c;比如存入两个1或两个"123"&#xff0c;只有1条数据会存入成功&#xff0c;但有个特殊情况&#xff0c;如果添加到set的值是引用类型&#xff0c;比如数组…

DataGear 4.5.1 发布,数据可视化分析平台

DataGear 4.5.1 发布&#xff0c;严重 BUG 修复&#xff0c;具体更新内容如下&#xff1a; 修复&#xff1a;修复SQL数据集对于DB2、SQLite等数据源预览时会报错的BUG&#xff1b;修复&#xff1a;修复系统对于MySQL、MariaDB等数据源中无符号数值类型有时报错的BUG&#xff1…

借助媛如意让ROS机器人turtlesim画出美丽的曲线-云课版本

首先安装并打开猿如意其次打开蓝桥云课ROS并加入课程在猿如意输入问题得到答案在蓝桥云课ROS验证如何通过turtlesim入门ROS机器人您可以通过以下步骤入门ROS机器人&#xff1a;安装ROS&#xff1a;您需要安装ROS&#xff0c;可以在ROS官网上找到安装指南。安装turtlesim&#x…

英文拼写检查:TX Spell .NET for .NET 10.0 Crack

用于 Windows 窗体应用程序的 TX Text Control .NET 的强大拼写检查和语言工具。 表现 可靠准确的拼写检查 使用 TX Spell .NET for Windows Forms&#xff0c;您可以为基于 TX Text Control 的应用程序添加极其快速、高度可靠和非常准确的拼写检查。将 TX Spell .NET for Wind…

mysql中的共享锁,排他锁,间隙锁,意向锁及死锁机制

一、前言&#xff08;以下均为读完 高性能Mysql第四版 后的个人理解&#xff0c;建议阅读&#xff0c;挺不错的&#xff09;在写锁机制前先简单贴出mysql InnoDB引擎中的事务特性与隔离级别&#xff1a;事务的ACID标准(1)原子性-atomicity&#xff1a;一个事务作为一个不可分割…

vue中使用富文本Tinymce

本文是直接引用vue-element-admin中的&#xff0c;在此记录方便下次使用&#xff0c;日后再详细注释。 再src下的components下创建Tinymce 下包含以下文件 index.vue是主体文件 plugins.js 是 插件配置 toolbar.js 是 粗体、斜体等配置 EditorImage.vue 是右上角的上传 封装后…

一文速学-GBDT模型算法原理以及实现+Python项目实战

目录 前言 一、GBDT算法概述 1.决策树 2.Boosting 3.梯度提升 使用梯度上升找到最佳参数 二、GBDT算法原理 1.计算原理 2.预测原理 三、实例算法实现 1.模型训练阶段 1&#xff09;初始化弱学习器 2&#xff09;对于建立M棵分类回归树​&#xff1a; 四、Python实现 …

Spring_让Spring 依赖注入彻底废掉

在Spring之基于注解方式实例化BeanDefinition&#xff08;1&#xff09;_chen_yao_kerr的博客-CSDN博客中&#xff0c;我们在末尾处分享了一个甜点&#xff0c;就是关于实现了BeanDefinitionRegistryPostProcessor也可以实例化bean的操作&#xff0c;首先需要去了解一下那篇博客…

宝塔(二):升级JDK版本

目录 背景 一、下载JDK17 二、配置环境变量 三、配置新的JDK路径 背景 宝塔的软件商店只有JDK8&#xff0c;不满足我当前项目所需的JDK版本&#xff0c;因此想对JDK版本进行升级&#xff0c;升级为JDK17。 一、下载JDK17 先进入 /usr/lib/jvm 目录 点击终端&#xff0c;进…

OpenCV——line、circle、rectangle、ellipse、polylines函数的使用和绘制文本putText函数以及绘制中文的方法。

学习OpenCV的过程中&#xff0c;画图是不可避免的&#xff0c;本篇文章旨在介绍OpenCV中与画图相关的基础函数。 1、画线条——line()函数 介绍&#xff1a; cv2.line(image, start_point, end_point, color, thickness)参数&#xff1a; image: 图像start_point&#xff1a…

拉链表(小记)

拉链表创建外部表将编写的orders.txt上传到hdfs创建一个增减分区表将orders表的数据传入ods_orders_inc查看分区创建历史表插入数据操作创建外部表 create database lalian; use lalian;create external table orders(orderId int,createDate string,modifiedTime string,stat…