【动态规划四】子序列问题

目录

leetcode题目

一、最长递增子序列

二、摆动序列

三、最长递增子序列的个数

四、最长数对链

五、最长定差子序列

六、最长的斐波那契子序列的长度

七、最长等差数列

八、等差数列划分 II


leetcode题目

一、最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/longest-increasing-subsequence/1.题目解析

子序列与子数组的区别在于:子序列可以不连续,但是要求元素顺序与原数组元素顺序不变~

因此子序列本质是包含子数组的~, 本题要求求出最长的严格递增子序列的长度

2.算法分析

1.状态表示

dp[i] 表示 以 i 位置元素为结尾的所有子序列中, 最长递增子序列的长度

2.状态转移方程

3.初始化
dp表全部初始化成1

4.填表顺序

从左向右

5.返回值

返回dp表的最大值

3.算法代码

class Solution {
public:int lengthOfLIS(vector<int>& nums) {//1.创建dp表int n = nums.size();vector<int> dp(n, 1);//2.填表 + 返回值int ret = 1;for(int i = 1; i < n; i++){for(int j = i - 1; j >= 0; j--){if(nums[j] < nums[i]) dp[i] = max(dp[i], dp[j] + 1);  }         ret = max(ret, dp[i]);}return ret;}
};

二、摆动序列

376. 摆动序列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/wiggle-subsequence/description/

1.题目解析

摆动序列是指相邻元素之间的差值正负交替,只有1个元素或2个元素也叫做摆动序列,求数组中满足摆动序列的最长子序列

2.算法分析

1.状态表示

f[i] 表示 以 i 位置元素为结尾的所有子序列中,最后呈现"上升"趋势,最长摆动序列的长度

g[i] 表示 以 i 位置元素为结尾的所有子序列中,最后呈现"下降"趋势,最长摆动序列的长度

2.状态转移方程

3.初始化

两个表都初始化成1

4.填表顺序

从左向右两个表一起填

5.返回值

两个表的最大值

3.算法代码

class Solution {
public:int wiggleMaxLength(vector<int>& nums){//1.创建dp表int n = nums.size();vector<int> f(n, 1), g(n, 1);//2.填表 + 返回值int ret = 1;for(int i = 1; i < n; i++){for(int j = 0; j < i; j++){if(nums[i] > nums[j])  f[i] = max(g[j] + 1, f[i]);if(nums[i] < nums[j])g[i] = max(f[j] + 1, g[j]);}ret = max(ret, max(f[i], g[i]));}return ret;}
};

三、最长递增子序列的个数

673. 最长递增子序列的个数 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/number-of-longest-increasing-subsequence/1.题目解析

求最长递增子序列的个数(严格递增)

2.算法分析

补充知识: 在数组中找出最大值出现的次数(要求遍历一次)

maxval = arr[0], count = 1, 遍历到数组中的元素x

1. x == maxval: count += 1

2. x < maxval: 无视

3. x > maxval: maxval = x, count = 0

1.状态表示

len[i]: 以 i 位置元素为结尾的所有的子序列中,最长递增子序列的长度

count[i]: 以 i 位置元素为结尾的所有的子序列中,最长递增子序列的个数

2.状态转移方程(参考上面的补充知识)

len[i] = count[i] = 1

j在[0, i-1]遍历, 在nums[j] < nums[i]的前提下:

①len[j] + 1 == len[i]:count[i] += count[j]

②len[j] + 1 < len[i]:无视

③len[j]+1 > len[i]:len[i] = len[j] + 1, count[i] = count[j]

3.初始化

两个表都初始化成1

4.填表顺序

从左往右两个表一起填

5.返回值

遍历len表的同时找出最大值出现的次数

3.算法代码

class Solution {
public:int findNumberOfLIS(vector<int>& nums) {//1.创建dp表int n = nums.size();vector<int> len(n, 1), count(n, 1);//2.填表 + 返回值int retlen = 1, retcount = 1;for(int i = 1; i < n; i++){for(int j = 0; j < i; j++){if(nums[j] < nums[i]){if(len[j] + 1 == len[i]) count[i] += count[j];else if(len[j] + 1 > len[i]) len[i] = len[j] + 1, count[i] = count[j];}}if(retlen == len[i]) retcount += count[i];else if(retlen < len[i]) retlen = len[i], retcount = count[i];}return retcount;}
};

四、最长数对链

646. 最长数对链 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/maximum-length-of-pair-chain/1.题目解析

给定一个数组,数组每个元素是一个数对[left, right], left 是严格 < right 的,[a, b], [c, d], [e, f]要能构成数对链,要求b < c, d < e,  求能构成的最长数对链的长度

2.算法分析

依旧是动态规划,但是在分析状态转移方程时,求dp[i]往往要依赖前一个dp[i-1]的值或者依赖后一个dp[i+1]的值,而本题分析到某一个数对时,无法保证要用到的上一个数对是在该数对的前面

比如 [[1, 2], [7, 8], [4, 5]]这个数组,最终形成的数对链中的[4, 5]就链到了[7, 8]的前面

因此我们需要先对数组排序,  而排序之后:

对于[a, b], [c, d],  d > c >= a, 推出 d > a, 因此[c, d]是不可能链到[a, b]后面的, 这样就可以得出状态转义移方程了~

1.状态表示

dp[i]: 以 i 位置元素为结尾的所有数对链中,最长的数对链的长度

2.状态转移方程

3.初始化

dp表全部初始化成1

4.填表顺序

从左往右填表

5.返回值

dp表的最大值

3.算法代码

class Solution {
public:int findLongestChain(vector<vector<int>>& pairs) {//排序sort(pairs.begin(), pairs.end());//1.创建dp表int n = pairs.size();vector<int> dp(n, 1);//2.填表 + 返回值int ret = 1;for(int i = 1; i < n; i++){for(int j = 0; j < i; j++){if(pairs[j][1] < pairs[i][0])dp[i] = max(dp[i], dp[j]+1);}ret = max(ret, dp[i]);}return ret;}
};

五、最长定差子序列

1218. 最长定差子序列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/description/1.题目解析

给定一个数组和difference, 返回最长定差子序列(相邻元素之间差为difference)的长度

2.算法分析

1.状态表示

dp[i]: 以 i 位置元素为结尾的所有子序列中,最长的定差子序列的长度

2.状态转移方程

3.初始化

hash[arr[0]] = 1

4.填表顺序

从左往右

5.返回值

dp表的最大值(哈希表的最大值)

3.算法代码

class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {//1.创建dp表(哈希表)unordered_map<int, int> hash; //arr[i]-dp[i]//2.初始化hash[arr[0]] = 1;//3.填表 + 返回值int ret = 1;for(int i = 1; i < arr.size(); i++){hash[arr[i]] = hash[arr[i] - difference] + 1; //这一行既保证了b不存在的时候,hash[i]是1, 也保证了b是最后一个bret = max(ret, hash[arr[i]]);}return ret;}
};

六、最长的斐波那契子序列的长度

873. 最长的斐波那契子序列的长度 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/length-of-longest-fibonacci-subsequence/1.题目解析

给定一个数组,求满足斐波那契式的最长的子序列的长度

2.算法分析

1.状态表示

dp[i][j]:以 i 位置 以及 j 位置 为结尾的所有子序列中,最长的斐波拉契子序列的长度

ps:开始是定义的dp[i], 但是推不出状态转移方程, 因为只知道子序列的个数,但是无法确定具体的斐波那契式的子序列,也就无法根据dp[i]前面的值推导出dp[i]~

题目七与题目八的状态表示也是同样的得到方法~

2.状态转移方程

3.初始化

把dp表中的所有值都初始化成2(只会用到dp表中 i < j 的位置)

4.填表顺序

dp[i][j] = dp[k][i] + 1,  k < i && i < j, 因此从上往下填表即可

5.返回值

ret < 3 ? 0 : dp表中的最大值

3.算法代码

class Solution 
{
public:int lenLongestFibSubseq(vector<int>& arr) {//1.将元素和下标绑定丢进哈希表int n = arr.size();unordered_map<int, int> hash;for(int i = 0; i < n; i++)hash[arr[i]] = i;//2.创建dp表vector<vector<int>> dp(n, vector<int>(n, 2));//3.填表+返回值int ret = 2;for(int j = 2; j < n; j++) //最后一个位置{for(int i = 1; i < j; i++) //倒数第二个位置{int a = arr[j] - arr[i];if(hash.count(a) && hash[a] < i) dp[i][j] = dp[hash[a]][i] + 1;ret = max(ret, dp[i][j]);}}return ret < 3 ? 0 : ret;}
};

七、最长等差数列

1027. 最长等差数列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/longest-arithmetic-subsequence/description/1.题目解析

给你一个整数数组 nums,返回 nums 中最长等差子序列的长度

2.算法分析

1.状态表示

dp[i][j]:以 i 位置 以及 j 位置 为结尾的所有子序列中,最长的等差序列的长度

2.状态转移方程

3.初始化

把dp表中的所有值都初始化成2(只会用到dp表中 i < j 的位置)

4.填表顺序

先固定倒数第2个数(b),再枚举倒数第一个数(c) --- 因为优化中,我们要保存的的是离i位置最近的a元素的下标,因此选择把b固定住,让c去移动

5.返回值

dp表中的最大值

3.算法代码

class Solution {
public:int longestArithSeqLength(vector<int>& nums) {//优化unordered_map<int, int> hash;hash[nums[0]] = 0;//1.创建dp表 + 初始化int n = nums.size();vector<vector<int>> dp(n, vector<int>(n, 2));//2.填表 + 返回值int ret = 2;for(int i = 1; i < n; i++) //固定倒数第2个数{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;ret = max(ret, dp[i][j]);}hash[nums[i]] = i; //i位置固定完之后,将nums[i]与i存入哈希表}return ret;}
};

八、等差数列划分 II

446. 等差数列划分 II - 子序列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/arithmetic-slices-ii-subsequence/1.题目解析

求数组中等差子序列的个数(本题的等差子序列至少要有3个元素)

2.算法分析

1.状态表示

dp[i][j]:以 i 位置 以及 j 位置 为结尾的所有子序列中,等差子序列的个数

2.状态转移方程

3.初始化

dp表所有的值都初始化0(因为最坏情况下,两个元素是无法构成等差子序列的)

4.填表顺序

固定倒数第1个数,枚举倒数第2个数

5.返回值

dp表所有元素的和

3.算法代码

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); //1.创建dp表 + 初始化vector<vector<int>> dp(n, vector<int>(n));//2.填表 + 返回值int sum = 0;for(int j = 2; j < n; j++) //固定倒数第1个数{for(int i = 1; i < j; i++) //枚举倒数第2个数{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;}}sum += dp[i][j];}}return sum;}
};

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

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

相关文章

Java入门——继承和多态(中)

组合 和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果. public class Student { ... } public class Teacher { ... } public class School { public Student[] students; public Teacher[] teachers; } 组合并没有涉及到特殊的语法(诸如 ex…

2023愚人杯 )————被遗忘的反序列化

<?php# 当前目录中有一个txt文件哦 error_reporting(0); show_source(__FILE__); include("check.php");class EeE{public $text;public $eeee;public function __wakeup(){if ($this->text "aaaa"){echo lcfirst($this->text);}}public functi…

量化交易:日内网格交易策略.md

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 本文将详细介绍日内网格交易策略的原理&#xff0c;并结合Python代码示例&#xff0c;展示如何在掘金平台上实现这一策略。 策略原理 日内网格交易策略的核心思想是在一天的交易时间内&#xff0c;通过设置多个买卖…

【谷粒商城】02安装和配置git

1.下载和安装git 地址&#xff1a;https://git-scm.com/download/win 傻瓜式安装 2.配置git DELLLJL MINGW64 ~/Desktop $ git config --global user.name "yufuabu"DELLLJL MINGW64 ~/Desktop $ git config --global user.email "463999534qq.com"DELL…

详解循环队列——链表与数组双版本

前言&#xff1a;本节内容主要是讲解循环队列。 在本篇中会讲到两个版本——数组版本、链表版本。本篇内容适合正在学习数据结构队列章节或者已经学过队列但对循环队列感觉模糊的友友们 。 首先先来看一下什么是循环队列 什么是循环队列 因为是刚开始讲解&#xff0c; 所以我们…

git知识总结

要知道 本地回退后&#xff0c;反悔了&#xff0c;可以恢复。前提是已经提交了&#xff0c;提交了就丢不了。 git reflog git reset --hard commitId 以前git push不让推&#xff0c;就是没有对应关系。第一次推要setxxx参数。 前奏 设置用户名和邮箱&#xff0c;设置错…

回溯之组合总和II

上一篇文章使用回溯解决了组合总和I&#xff0c;这次使用回溯解决组合总和II&#xff0c;下面先给出回溯的模板代码。 private void backtracking(参数1,参数2,...){if(递归终止条件){收集结果;return;}for(遍历集合){处理;backtracking(参数1,参数2,...); // 递归;回溯;} }组…

5. FactoryTalk View SE -- 模拟量趋势记录

step1&#xff1a; 在项目列表下找到数据记录–数据记录模型–新建。 step2&#xff1a;更改描述、文件标识符、存储格式。 step3&#xff1a;更改文件缓存路径。 step4&#xff1a;更改缓存文件保存的周期。 step5&#xff1a;5s保存一次数据。 step6&#xff1a;添加标…

从零开始搭建Springboot项目脚手架2:配置文件、返回值、日志等

1、多个环境与配置文件 2、统一返回值 返回值包括两种场景&#xff1a;正常controller的返回、异常发生之后返回 正常controller的返回&#xff1a;通过在controller的默认返回Response实现 异常发生之后返回&#xff1a;通过全局异常处理统一捕获返回 首先创建类StatusCode…

[Spring Cloud] (7)gateway防重放拦截器

文章目录 简述本文涉及代码已开源Fir Cloud 完整项目防重放防重放必要性&#xff1a;防重放机制作用&#xff1a; 整体效果后端进行处理 后端增加防重放开关配置签名密钥 工具类防重放拦截器 前端被防重放拦截增加防重放开关配置请求头增加防重放签名处理防重放验证处理函数bas…

打造清洁宜居家园保护自然生态环境,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境&#xff0c;作为我们人类赖以生存的家园&#xff0c;其健康与否直接关系到我们的生活质量。然而&#xff0c;近年来&#xff0c;一些不法分子为了个人私利&#xff0c;在河边、路边等公共区域肆意倾倒垃圾&#xff0c;严重破坏了环境的健康与平衡。这种行为不仅损…

18.04版本的ubuntu没有连接网络的图标(坑人版)

以下更新内核别看&#xff0c;因为后面安装驱动报一堆错误!!! 不升级内核成功方法跳转连接&#xff1a;https://blog.csdn.net/weixin_53765004/article/details/138771613?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2213877…

单调栈问题

原理 单调栈的核心原理是&#xff1a;在栈内保持元素的单调性&#xff08;递增或递减&#xff09; 单调递增栈&#xff1a; 用于处理“下一个更小的元素”问题。当新元素比栈顶元素小或等于时&#xff0c;直接入栈&#xff1b;否则&#xff0c;一直从栈顶弹出元素&#xff0c…

OBS直播二次开发_OBS直播软件介绍

OBS工作室版 免费且开源的用于视频录制以及直播串流的软件。 下载以在Windows, Mac以及Linux上简单且快速的开始串流。 功能 实时高性能的视频/音频捕捉与混合,以及无限的场景模式使您可以通过自定义实现无缝转换。为视频源设计的滤镜例如图片蒙版,色彩校正,色度/色彩键控…

软件体系结构风格

目录 一、定义 二、.经典软件体系结构风格&#xff1a; 1.管道和过滤器 2.数据抽象和面向对象系统 3.基于事件系统&#xff08;隐式调用&#xff09; 4.分层系统 5.仓库 6.C2风格 7.C/S 8.三层C/S 9.B/S 题&#xff1a; 一、定义 软件体系机构风格是描述某一特定应用…

通过内网穿透实现远程访问个人电脑资源详细过程(免费)(NatApp + Tomcat)

目录 1. 什么是内网穿透 2. 内网穿透软件 3. NatApp配置 4. 启动NatApp 5. 通过内网穿透免费部署我们的springboot项目 通过内网穿透可以实现远程通过网络访问电脑的资源&#xff0c;本文主要讲述通过内网穿透实现远程访问个人电脑静态资源的访问&#xff0c;下一章节将讲…

C语言/数据解构——(随即链表的复制)

一.前言 嗨嗨嗨&#xff0c;大家好久不见。已经有好几天没更新了。今天我们就分享一道链表题吧——随即链表的复制https://leetcode.cn/problems/copy-list-with-random-pointer废话不多说&#xff0c;让我们直接开始今天的题目分享吧。 二.正文 1.1题目描述 他和单链表不同…

华为OD机试 - 求幸存数之和(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

机器学习面试篇

如何理解机器学习数据集的概念 数据集是机器学习的基础&#xff0c;它包括了用于训练和测试模型所需的数据。数据集通常以矩阵的形式存在&#xff0c;其中每一行代表一个样本&#xff08;或实例&#xff09;&#xff0c;每一列代表一个特征&#xff08;或属性&#xff09;。…

JVM从1%到99%【精选】-类加载子系统

目录 1.类的生命周期 1.加载 2.连接 3.初始化 2.类的加载器 1.类加载器的分类 2.双亲委派机制 3.面试题&#xff1a;类的双亲委派机制是什么&#xff1f; 4.打破双亲委派机制 1.类的生命周期 类加载过程&#xff1a;加载、链接&#xff08;验证、准备、解析&a…