【动态规划】C++ 子序列问题(递增子序列、数对链、定差子序列、斐波那契子序列...)

文章目录

  • 1. 前言
  • 2. 例题
    • 最长递增子序列
  • 3. 算法题
    • 3.1_摆动序列
    • 3.2_最长递增子序列的个数
    • 3.3_最长数对链
    • [3.4_ 最长定差子序列](https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/description/)
    • 3.5_最长的斐波那契子序列的长度
    • 3.6_最长等差数列
    • 3.7_等差数列划分II-子序列

1. 前言

关于 动态规划的理解 与例题,点击👇

【动态规划】C++解决斐波那契模型题目(三步问题、爬楼梯、解码方法…)

并且我们之前做过有关 子数组的dp问题:C++子数组dp问题

子序列与子数组的区别主要在于:子数组是连续的,即下标连续的不中断的;而子序列可以连续可以不连续(子序列的范围更大)。

有了上面的经验,我们来解下面 子序列 问题

2. 例题

通过下面一道例题理解子序列问题,以及如何解子序列dp问题:

最长递增子序列

在这里插入图片描述

思路

  • 题意分析
    1. 题目要求找到 最长的递增子序列的长度

根据题目要求,我们设置状态表示:

在这里插入图片描述
根据上面的思路,我们可以用两个for循环编写呆猫:

代码

class Solution {
public:int lengthOfLIS(vector<int>& nums) {int n = nums.size();// 创建dp数组 + 初始化vector<int> dp(n, 1); // dp[i]: 以i为结尾,严格递增子序列的最长长度int ret = 1; // 结果:for(int i = 1; i < n; ++i){for(int j = 0; j <= i-1; ++j){if(nums[j] < nums[i])dp[i] = max(dp[j]+1, dp[i]);}ret = max(ret, dp[i]);}return ret;}
};

需要注意的是:本题的最优解法并不是利用动态规划,但通过本道例题可以很好的对子序列问题进行理解:

(顺带贴上更优解法:贪心 + 二分)

class Solution {
public:int lengthOfLIS(vector<int>& nums) {// 贪心vector<int> ret;ret.push_back(nums[0]);for(int i = 0; i < nums.size(); ++i){if(nums[i] > ret.back()) {ret.push_back(nums[i]);} else { // 二分查找int left = 0, right = ret.size() - 1;while(left < right){int mid = (left + right) >> 1;if(ret[mid] < nums[i])left = mid + 1;elseright = mid;}ret[left] = nums[i]; // 插入}}return ret.size();}
};

3. 算法题

通过《最长递增子序列》一题给的经验,我们来解下面的算法题:

3.1_摆动序列

在这里插入图片描述

思路

  • 题意分析
    1. 在子数组问题中,我们曾做过一道题《最长湍流子数组》,和本题类似,我们根据它的经验,可以创建两个dp表:

在这里插入图片描述
在这里插入图片描述

代码

class Solution {
public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();// dp数组的创建 + 元素初始化vector<int> f(n, 1); // 以i为结尾,最后呈现“上升”状态的 子序列的最长长度vector<int> g(n, 1); // 以i为结尾,最后呈现“下降”状态的 子序列的最长长度int ret = 1; // 最终结果for(int i = 1; i < n; ++i){for(int j = 0; j <= i - 1; ++j){if(nums[j] < nums[i]) f[i] = max(g[j]+1, f[i]); // 可以将第 i 个元素加入到以第 j 个元素结尾的递增子序列中if(nums[j] > nums[i]) g[i] = max(f[j]+1, g[i]);}ret = max(max(f[i], g[i]), ret);}return ret;}
};

3.2_最长递增子序列的个数

在这里插入图片描述

思路

  • 题意分析
    1. 之前的例题,求的是最长递增子序列的长度,这里要的是 最长递增子序列的 个数
    2. 即我们不仅需要考虑长度,也需要考虑个数,即两个状态,可以设置两个dp表
    3. 一个小demo: 如何找到数组中最大值的出现次数?
      • 遍历数组会有三种情况:
        • x < maxVal: 无视
        • x == maxVal: count++
        • x > maxVal: 更新maxVal,count = 0

根据这个思路,我们进行分析:

在这里插入图片描述

在这里插入图片描述

代码

class Solution {
public:int findNumberOfLIS(vector<int>& nums) {int n = nums.size();// 创建dp数组 + 初始化元素vector<int> len(n, 1), count(n, 1); // 分别为:以i为结尾,1.递增子序列的最长长度 与 2.最长递增子序列的个数int retLen = 1, retCount = 1;for(int i = 1; i < n; ++i){for(int j = 0; j <= i-1; ++j){if(nums[j] < nums[i]){if(len[j] + 1 == len[i]) count[i] += count[j]; // 第j位恰好与i组成最长递增子序列// else if(len[j] + 1 < len[i]) continue; // 无视此次,可以注释掉else if(len[j] + 1 > len[i]) len[i] = len[j] + 1, count[i] = count[j]; // j的递增序列更长}}// 更新结果if(retLen == len[i]) retCount += count[i];else if(retLen < len[i]){retCount = count[i];retLen = len[i];}// else 无视该情况}return retCount;}
};

3.3_最长数对链

在这里插入图片描述

思路

  • 题意分析
    1. 题目要求找到 最长的数对链,数对链即对于[a, b], [c, d]仅当b < c时,才成立[a, b] -> [c, d]
    2. 根据这个规律,我们在找子序列时,首先要保证不能存在一种情况:
      • 令存在三个数对x, y, z
      • 当我们遍历到y时,即使不一定有y->z,但一定不能有z->y
    3. 根据数对链的性质,我们只需要 对数组根据首位元素进行排序 即可。
    4. 由此可以设置状态表示:

在这里插入图片描述

代码

class Solution {
public:int findLongestChain(vector<vector<int>>& pairs) {// 预处理:排序数组sort(pairs.begin(), pairs.end());int n = pairs.size();// 创建dp数组 + 初始化元素vector<int> dp(n, 1); // dp[i]: 以i为结尾,数对链的最长长度int ret = 1; // 结果for(int i = 1; i < n; ++i){for(int j = 0; j <= i-1; ++j){if(pairs[j][1] < pairs[i][0]){dp[i] = max(dp[j] + 1, dp[i]);}}ret = max(ret, dp[i]);}return ret;}
};

3.4_ 最长定差子序列

在这里插入图片描述

思路

  • 题意分析
    1. 题目要求找 最长的定差子序列的长度 ,定差子序列即等差数列,给定了公差difference。
    2. 根据题目要求设置装填表示:

在这里插入图片描述
在这里插入图片描述

代码

class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {unordered_map<int, int> hash; // arr[i] : dp[i]hash[arr[0]] = 1; // 初始化int ret = 1, n = arr.size();for(int i = 1; i < n; ++i){hash[arr[i]] = hash[arr[i] - difference] + 1; // dp[i] = dp[j] + 1,可以保证是最后一个bret = max(ret, hash[arr[i]]);}return ret;}
};

3.5_最长的斐波那契子序列的长度

在这里插入图片描述

思路

  • 题意分析
    1. 题目要求找 最长的斐波那契子序列的长度
    2. 我们首先试着将状态表示设置为:
      • dp[i]:以i为结尾的所有子序列中,最长斐波那契子序列的长度
      • 当我们尝试写状态表达式时,没有办法正确找到(斐波那契子序列的判断至少需要两个元素,通过差值我们可以判断另一位是什么)
    3. 所以我们更改状态表示:

在这里插入图片描述
在这里插入图片描述

代码

class Solution {
public:int lenLongestFibSubseq(vector<int>& arr) {int n = arr.size();// 创建dp数组 + 元素初始化vector<vector<int>> dp(n, vector<int>(n, 2));// 哈希表:值映射下标unordered_map<int, int> hash;for(int i = 0; i < arr.size(); ++i)hash[arr[i]] = i; int ret = 2; // 返回值for(int j = 2; j < n; ++j){for(int i = 1; i < j; ++i){// 填表int a = arr[j] - arr[i];if(a < arr[i] && hash.count(a))dp[i][j] = dp[hash[a]][i] + 1; // ret = max(ret, dp[i][j]);}}return ret == 2 ? 0 : ret;}
};

3.6_最长等差数列

在这里插入图片描述

思路

  • 题意分析
    1. 本题与前面的斐波那契子序列有相似之处,下面进行状态表示的设置:

在这里插入图片描述
在这里插入图片描述

代码

class Solution {
public:int longestArithSeqLength(vector<int>& nums) {int n = nums.size();unordered_map<int, int> hash; // <元素 下标>hash[nums[0]] = 0;vector<vector<int>> dp(n, vector<int>(n, 2));// dp表的创建+初始化int ret = 2;for(int i = 1; i < n; ++i) // 固定倒数第二个数{for(int j = i + 1; j < n; ++j) // 固定最后一个数{int a = 2 * nums[i] - nums[j];if(hash.count(a))dp[i][j] = dp[hash[a]][i] + 1; // dp[k][i] + 1ret = max(ret, dp[i][j]);}hash[nums[i]] = i; // 保存最近的元素下标 }return ret;}
};

3.7_等差数列划分II-子序列

在这里插入图片描述

思路

  • 题意分析
    1. 前面的题要求最长等差数列的长度,而本题要求个数
    2. 对于本题我们可以采用上题思路的①优化以及①填表顺序

代码

class Solution {
public:int numberOfArithmeticSlices(vector<int>& nums) {int n = nums.size();unordered_map<long long, vector<int>> hash; // <元素 下标>for(int i = 0; i < n; ++i) hash[nums[i]].push_back(i);vector<vector<long long>> dp(n, vector<long long>(n, 0));// dp表的创建+初始化long long sum = 0;for(int j = 2; j < n; ++j) // 固定倒数第二个数{for(int i = 1; i < j; ++i) // 固定最后一个数{long long a = (long long)2 * nums[i] - nums[j];if(hash.count(a))for(auto k : hash[a])if(k < i)   dp[i][j] += dp[k][i] + 1; // += dp[k][i] + 1sum += dp[i][j];}}return sum;}
};

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

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

相关文章

Spring Boot:Web应用开发之增删改查的实现

Spring Boot 前言实现增删改查功能 前言 增删改查功能作为 Web 应用中的基础且重要的组成部分&#xff0c;是基本的数据库操作&#xff0c;也是实现业务逻辑和功能的关键要素。下面简单介绍使用 Spring Boot 实现增删改查的功能。 实现增删改查功能 在上一章 Spring Boot&am…

安装无法完成。安装Autodesk产品时出现错误103

解决方法如下 打开autoremove&#xff0c;点击扩展功能&#xff0c;输入103&#xff0c;点击搜索 注意 修复过程根据情况可能会很慢 等待提示修复成功&#xff0c;再尝试重新安装软件。 软件每周六选择其他方式登录免费使用

海康Visionmaster-常见问题排查方法-启动失数

问题2&#xff1a;VM无法启动&#xff0c;报错&#xff1a;参数错误&#xff1b;  问题原因&#xff1a;客户电脑环境异常导致代理启动失败。  解决方法&#xff1a;安装运行时库&#xff0c;并测试代理能否正常启动,步骤如下&#xff1a; ① 尝试双击代理进程&#xff…

Linux之yum和vim的使用

一、yum的使用 yum 后面跟install要安装的文件名&#xff1a; 若你要安装的文件已经存在&#xff0c;则会出现&#xff1a; 要删除文件&#xff1a; yum remore文件名即可删除 在我们安装完lrzsz之后&#xff0c;可以用rz指令和sz指令&#xff1a; rz指令可以从window窗口中…

【Linux开发实用篇】Webmin和宝塔

可视化工具 Webmin宝塔 Webmin Webmin是功能强大的基于Web的Linux/Unix管理工具 下载地址&#xff1a;http://download.webmin.com/download/yum/ 使用wget指令下载&#xff1a;http://download.webmin.com/download/yum/webmin-1.700-1.noarch.rpm 然后进行安装&#xff1a; …

第07-5章 传输层详解

7.1 传输层概述 分段及封装应用层送来的数据&#xff1a;应用层以字节流的形式给传输层传输数据&#xff0c;传输层会把字节流分段&#xff0c;并给每段封装 由应用程序产生应用进程&#xff0c;由应用进程产生进程端口号&#xff0c;由端口号提供相应的服务 如何查看本…

项目实践---贪吃蛇小游戏(下)

对于贪吃蛇小游戏&#xff0c;最主要的还是主函数部分&#xff0c;这里就和大家一一列举出来&#xff0c;上一章已经写过头文件了&#xff0c;这里就不多介绍了。 首先就是打印桌面&#xff0c;也就是背景&#xff0c;则对应的代码为&#xff1a; void SetPos(short x, short …

(四)Servlet教程——Maven的安装与配置

1.在C盘根目录下新建一个Java文件夹,该文件夹用来放置以下步骤下载的Maven&#xff1b; 2. 下载Maven的来源有清华大学开源软件镜像站和Apache Maven的官网&#xff0c;由于清华大学开源软件镜像站上只能下载3.8.8版本以上的Maven&#xff0c;我们选择在Apache Maven的官网上下…

VulnHub靶机 DC-8 打靶实战 详细渗透过程

VulnHub靶机 DC-8 打靶 详细渗透过程 目录 VulnHub靶机 DC-8 打靶 详细渗透过程一、将靶机配置导入到虚拟机当中二、渗透测试流程主机发现端口扫描Web渗透SQL注入登录后台反弹shell提权 一、将靶机配置导入到虚拟机当中 靶机地址&#xff1a; https://www.vulnhub.com/entry/…

Docker容器概念介绍与基本管理

前言 在软件开发和部署环境中&#xff0c;使用 Docker 等容器技术可以帮助团队实现快速、一致、可靠的应用程序部署&#xff0c;提高开发效率和应用程序的可移植性。 目录 一、虚拟化产品介绍 1. 云服务模型 1.1 IaaS 1.2 PaaS 1.3 SaaS 1.4 DaaS 2. 产品介绍 2.1 虚…

BUUCTF---[SWPU2019]神奇的二维码

1、下载附件是一张二维码&#xff0c;拿去扫描得到了flag 2、拿去提交是错的&#xff08;不会这么简单哈哈哈&#xff09;&#xff0c;常规操作在kali中分析 3、分离发现图片里面有东西 4、查看txt&#xff0c;发现里面有一串字符&#xff0c;解码后为 5、查看文档&#xff0c…

「ChatGPT」掀起新一轮AI热潮!超越GPT-4 Turbo,商汤日日新大升级!

目录 拳打 GPT-4 Turbo &#xff0c;脚踢 DALLE 3 端侧大模型&#xff0c;唯快不破 AI 应用落地需要一个即插即用的大模型超市 并不存在 AI 这个行业&#xff0c;只有 AI行业&#xff0c;强调 AI 需要与传统产业合作&#xff0c;这种关系是结合与赋能&#xff0c;而不是颠覆…

【提示学习论文】BlackVIP: Black-Box Visual Prompting for Robust Transfer Learning论文原理

BlackVIP: Black-Box Visual Prompting for Robust Transfer Learning BlackVIP:稳健迁移学习的黑盒视觉提示 问题 黑盒白盒&#xff1f; 黑盒和白盒的概念与对预训练模型内部参数的了解程度相关。黑盒指的是对预训练模型的参数和结构缺乏详细了解&#xff0c;通常只能通过使…

Python自学之路--001:Python + PyCharm安装图文详解教程

目录 1、概述 2、Python解释器 2.1、下载 2.2、Python安装 2.3、Python环境变量配置&#xff0c;必选项 3、PyCharm安装 3.1、PyCharm下载 3.2、PyCharm安装 4、建一个Hello World 5、Phcarm设置 5.1、Phcarm汉化 5.2、Phcarm工具栏显示在顶部 5.3、Phcarm通过pip安…

[2021年最新]国产时序性数据TDenige入门

一、TDenige简介 TDengine&#xff1a;是涛思数据面对高速增长的物联网大数据市场和技术挑战推出的创新性的大数据处理产品&#xff0c;它不依赖任何第三方软件&#xff0c;也不是优化或包装了一个开源的数据库或流式计算产品&#xff0c;而是在吸取众多传统关系型数据库、NoS…

25计算机考研院校数据分析 | 复旦大学

复旦大学(fudan University)&#xff0c;简称"复旦”&#xff0c;位于中国上海&#xff0c;由中华人民共和国教育部直属&#xff0c;中央直管副部级建制&#xff0c;位列985工程、211工程、双一流A类&#xff0c;入选“珠峰计划"、"111计划""2011计划…

zabbix自动发现和自动注册

一、zabbix自动发现 1.1 确保客户端上的zabbix-agent2服务器状态正常 1.2 在web页面删除原有的客户端主机 1.3 在服务端和客户端上配置hosts 1.4 web端配置自动发现 二、zabbix自动注册 2.1 环境配置 2.2 修改zabbix-agent2配置文件 过滤非#或非&#xffe5;开头的内容 2.3 we…

应用实战|只需几步,即可享有外卖订餐小程序

本示例是一个简单的外卖查看店铺点菜的外卖微信小程序&#xff0c;小程序后端服务使用了MemFire Cloud&#xff0c;其中使用到的MemFire Cloud功能包括&#xff1a; 其中使用到的MemFire Cloud功能包括&#xff1a; 云数据库&#xff1a;存储外卖微信小程序所有数据表的信息。…

解决Linux CentOS 7安装了vim编辑器却vim编辑器不起作用、无任何反应

文章目录 前言一、解决vim不起作用&#xff08;卸载重新安装&#xff09;1.重新安装vim2.测试vim是否能正常使用 二、解决vim: error while loading shared libraries: /lib64/libgpm.so.2: file too short报错三、解决vim编辑器不能使用方向键和退格键问题 remove vim-common …

【S32DS RTD实战】-1.5-S32DS使用Post-Build调用第三方插件-自动对生成的s19,Hex,Bin文件二次编辑

<--返回「Autosar_MCAL高阶配置」专栏主页--> 案例背景&#xff1a; 在《【S32DS RTD实战】-1.3-S32K3工程生成S19&#xff0c;BIN&#xff0c;Hex文件&#xff0c;以及Post-build steps的妙用_s32ds如何生成s19或hex文件-CSDN博客https://blog.csdn.net/qfmzhu/articl…