算法系列--动态规划--子序列(2)

💕"你可以说我贱,但你不能说我的爱贱。"💕
作者:Mylvzi
文章主要内容:算法系列–动态规划–子序列(2)
在这里插入图片描述
今天带来的是算法系列--动态规划--子序列(2),包含了关于子序列问题中较难的几道题目(尤其是通过二维状态表示来推导状态转移方程)

1.最⻓定差⼦序列

链接:
https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/description/
在这里插入图片描述
分析:

  • 状态表示:dp[i]:以i为结尾的,最长的定差子序列的长度
  • 状态转移方程:if(hash.contains(a - difference)) dp[i] = dp[k] + 1
  • 优化:由于要寻找a-difference与其对应的下标k,所以我们可以利用一个哈希表来建立数值与下标之间的映射关系

在这里插入图片描述

代码:

class Solution {public int longestSubsequence(int[] arr, int difference) {Map<Integer,Integer> hash = new HashMap<>();int ret = 1;// 记录最值for(int a : arr) {hash.put(a,hash.getOrDefault(a-difference, 0 ) + 1);// 将当前位置插入到哈希表中ret = Math.max(ret,hash.get(a));// 更新最值}return ret;}
}

2.最⻓的斐波那契⼦序列的⻓度

链接:
https://leetcode.cn/problems/length-of-longest-fibonacci-subsequence/

分析:
在这里插入图片描述

代码:

class Solution {public int lenLongestFibSubseq(int[] nums) {int n = nums.length;int[][] dp = new int[n][n];// 初始化为2for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) dp[i][j] = 2;}Map<Integer,Integer> hash = new HashMap<>();for(int i = 0; i < n; i++) hash.put(nums[i], i);// 将数组中的值和下标存入到哈希表之中hash.put(nums[0],0);int ret = 2;// 填表for(int j = 1; j < n; j++) {for(int i = 0; i < j; i++) {int a = nums[j] - nums[i];// 得到前一个位置的数if(a < nums[i] && hash.containsKey(a)) {//必须包含 且下标在i之前dp[i][j] = dp[hash.get(a)][i] + 1;// 更新}ret = Math.max(ret,dp[i][j]);// 更新最值}}return ret < 3 ? 0 : ret;// 处理极端情况(无fib数列)}
}

3.最⻓等差数列

链接:
https://leetcode.cn/problems/longest-arithmetic-subsequence/description/

在这里插入图片描述

分析:
这道题笔者最开始经过分析,认为这道题和最长的斐波那契子序列的解法相同,同样的是利用固定两个数的方式来确定完整的等差数列,但是并未通过,反思如下:

  1. 最长的斐波那契子序列这道题目中,题目明确了整个序列是严格递增的,但是本题并没有这样的要求.这就加大了本题的难度,如果是严格递增的,就不需要考虑值重复的问题,但本题需要考虑,此时就需要使用<key,下标数组>这样的方式来保存值与下标之间的映射关系,在获取最长的长度时,我们需要的离倒数第二个数最近的元素的下标(此时的dp表中对应的长度是最长的),所以在得到nums[i] - nums[j]之后,还需要去便利整个下标数组,拿到最大的下标,进而获得最大的长度
  2. 上述方式固然是一种解决方案,但是时间复杂度也很高,优化策略:一边dp,一边保存离nums[i]最近的值的下标
  3. 如何实现上述策略呢?要想实现上述策略,需要我们在填表的时候采用固定倒数第二个数,枚举后一个数的方式,这样能保证我们获取到的a是离nums[i]最近的位置

代码:

class Solution {public int longestArithSeqLength(int[] nums) {int n = nums.length;int[][] dp = new int[n][n];// 初始化为2for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) dp[i][j] = 2;}Map<Integer,Integer> hash = new HashMap<>();hash.put(nums[0],0);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.containsKey(a)) {//必须包含 且下标在i之前dp[i][j] = dp[hash.get(a)][i] + 1;// 更新}ret = Math.max(ret,dp[i][j]);// 更新最值}hash.put(nums[i],i);}return ret;}
}

另一种状态表示:

上述需要固定两个数的原因在于无法通过一个数直接找到一个完整的等差序列,更本质的原因在于我们不知道公差究竟是多少,但是我们可以将i位置对应的所有公差都存入到dp表之内,这样就能枚举所有的d的情况,所以我们可以使用以i位置为结尾,公差为d的最长的等差序列的长度

class Solution {public int longestArithSeqLength(int[] nums) {int n=nums.length;int[][] dp=new int[n][1001];int maxLen=0;//保存结果for(int k=1;k<n;k++){for(int j=0;j<k;j++){int d=nums[k]-nums[j]+500;//统一加偏移量,使下标非负dp[k][d]=dp[j][d]+1; //根据 d 去填充dp[k][d]maxLen=Math.max(maxLen,dp[k][d]);//维护最大值}}return maxLen+1;}
}

但是笔者觉得第二种写法并不是特别好,有点投机取巧之嫌(其实只要能做出来就好)

4.等差数列划分II - ⼦序列

链接:
https://leetcode.cn/problems/arithmetic-slices-ii-subsequence/description/
在这里插入图片描述

分析:

  • 之前做过等差数列划分I,那道题是子数组,强调必须是连续的,但是本题是子序列,是可以不连续的
  • 如果做过上面的第二道题最长的等差序列,本题其实很容易想到思路,同样的,由于之定义一个状态无法表示确定状态,所以需要两个状态
  • dp[i][j]:以i,j位置(i < j)为结尾的所有等差数列的个数
  • 思路和最长的等差序列也是相似的,首先固定倒数第一个数,接着从0遍历第二个数,找到符合条件的值后,获得其对应的下标,进而获得dp表中的值
  • 一分析觉得这道题和最长的等差序列那道题很像,但是那道题只用保存最长的长度就行,这道题需要用一个数组保存相同值的所有下标,所以在哈希表中建立的映射关系应该是<key,int[]>(笔者想到了这点,但是不知道怎么表示int[],导致此题没做出来,惭愧惭愧),实际上只要存储一个List就行,遍历的时候使用for each遍历即可

代码:

class Solution {private int ret;// 返回值public int numberOfArithmeticSlices(int[] nums) {int n = nums.length;int[][] dp = new int[n][n];// 存放值与相同值的所有下标(下标应该是一个下标数组)Map<Long,List<Integer>> hash = new HashMap<>();for(int i = 0; i < n; i++) {long tmp = (long)nums[i];if(!hash.containsKey(tmp))hash.put(tmp,new ArrayList<Integer>());hash.get(tmp).add(i);}for(int j = 2; j < n; j++) {for(int i = 1; i < j; i++) {long a = 2L * nums[i] - nums[j];if(hash.containsKey(a)) {// 遍历下标数组(注意相同的一个值的下标有多个,而我们要求出所有的等差序列的个数,所以所有的下标都要加上)for(int k : hash.get(a)) {if(k < i) dp[i][j] += (dp[k][i] + 1);// +1表示的是 k,j,i三个数字组成一个新的等差数列else break;}}ret += dp[i][j];// 计算当前位置的和}}return ret;}
}

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

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

相关文章

数据结构从入门到精通——快速排序

快速排序 前言一、快速排序的基本思想常见方式通用模块 二、快速排序的特性总结三、三种快速排序的动画展示四、hoare版本快速排序的代码展示普通版本优化版本为什么要优化快速排序代码三数取中法优化代码 五、挖坑法快速排序的代码展示六、前后指针快速排序的代码展示七、非递…

VSCode最强插件合集,助你代码开发效率翻倍!

大家好&#xff0c;我是宝哥。 今天给大家推荐14个VSCode靠前的编程辅助插件&#xff0c;它们可以帮助你提高代码编写、调试、阅读和管理效率。 1.ESLint 简介&#xff1a;用于检查JavaScript代码的语法和风格错误。 功能特色&#xff1a;支持多种规则&#xff0c;可以自定义规…

XSS-labs详解

xss-labs下载地址https://github.com/do0dl3/xss-labs 进入靶场点击图片&#xff0c;开始我们的XSS之旅&#xff01; Less-1 查看源码 代码从 URL 的 GET 参数中取得 "name" 的值&#xff0c;然后输出一个居中的标题&#xff0c;内容是 "欢迎用户" 后面…

STM32利用串口标准库发送字节,发送数组,发送字符串,发送数字,实现printf功能。

早晨到现在刚刚完成的功能&#xff1a;发送字节&#xff0c;发送数组&#xff0c;发送字符串&#xff0c;发送数字&#xff0c;实现printf功能。 当然这是建立在昨天学习使用串口发送数据的基础上&#xff0c;新建立的功能函数&#xff0c;咱们先来看看这次实验的结果吧&#…

C语言经典算法-8

文章目录 其他经典例题跳转链接41.基数排序法42.循序搜寻法&#xff08;使用卫兵&#xff09;43.二分搜寻法&#xff08;搜寻原则的代表&#xff09;44.插补搜寻法45.费氏搜寻法 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三角形 4. 三色棋 5. 老鼠…

安捷伦Agilent E8364C网络分析仪

181/2461/8938产品概述&#xff1a; Agilent E8364C 网络分析仪是 Agilent PNA 系列网络分析仪&#xff08;高性能网络分析仪&#xff09;的一部分&#xff0c;具有满足您关键需求的最高准确度。Agilent E8364C 具有 10 MHz 至 50 GHz 的宽频率范围&#xff0c;并具有 2 个端口…

刀具磨损失效形式

目录 磨料磨损 扩散磨损 粘着磨损 腐蚀磨损 氧化磨损 表面疲劳磨损 热点磨损 刀具失效形式有磨损、破损和折断。在微小孔钻削中&#xff0c;磨损形式有很多种&#xff0c;如磨料磨损、扩散磨损、粘着磨损、腐蚀磨损、氧化磨损、表面疲劳磨损、热点磨损等。 磨料磨损 磨…

python电影院订票信息管理系统flask-django-php-nodejs

当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#xff0c;国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统电影院订票采取了人工的管理方法&#xff0c;但…

leetcode 20.有效的括号 JAVA

题目 思路 括号的匹配&#xff0c;这是一道经典的栈的应用问题。 给我们一个字符串&#xff0c;当我们遍历到左括号时&#xff0c;让其入栈。当我们遍历到右括号时&#xff0c;让栈顶元素出栈&#xff0c;看看栈顶的元素是否和遍历到的右括号匹配。不匹配的话直接false,匹配的…

基于FPGA的FFT图像滤波设计

1.FFT滤波算法介绍 FFT滤波就是通过傅里叶运算将图像转换到频域空间&#xff0c;然后在频域中对图像进行处理&#xff0c;最后将处理后的图像通过傅里叶逆运算将图像转会到时域空间。 在频域空间中&#xff0c;我们能够更好的对图像的噪声进行分析&#xff0c;然后找出相关规律…

Kubernetes(k8s)集群健康检查常用的五种指标

文章目录 1、节点健康指标2、Pod健康指标3、服务健康指标4、网络健康指标5、存储健康指标 1、节点健康指标 节点状态&#xff1a;检查节点是否处于Ready状态&#xff0c;以及是否存在任何异常状态。 资源利用率&#xff1a;监控节点的CPU、内存、磁盘等资源的使用情况&#xf…

YOLOv8 | 注意力机制 | ShuffleAttention注意力机制 提升检测精度

YOLOv8成功添加ShuffleAttention ⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/1Aqzu YOLOv8涨点专栏…

mysql字段多个值,mybatis/mybatis-plus匹配查询

mysql中有一个字段是字符串类型的&#xff0c;category字段值有多个用逗号分割的&#xff0c;例如&#xff1a;娱乐,时尚美妆,美食 。现在想实现这么一个功能&#xff0c; 前端传参 字符串&#xff0c;美食,娱乐。现在想在mybatis的xml中实现&#xff0c;查询&#xff0c;能查到…

软件测试 -- Selenium常用API全面解答(java)

写在前面 // 如果文章有问题的地方, 欢迎评论区或者私信指正 目录 什么是Selenium 一个简单的用例 元素定位 id定位 xpath定位 name定位 tag name 定位和class name 定位 操作元素 click send_keys submit text getAttribute 添加等待 显示等待 隐式等待 显示等…

【wubuntu】披着Win11皮肤主题的Ubuntu系统

wubuntu - 一款外观类似于 Windows 的 Linux 操作系统&#xff0c;没有任何硬件限制。以下是官方的描述 Wubuntu is an operating system based on Ubuntu LTS that has a similar appearance to Windows using the open-source themes. Wubuntu also comes with a set of adva…

JavaScript 权威指南第七版(GPT 重译)(二)

第四章&#xff1a;表达式和运算符 本章记录了 JavaScript 表达式以及构建许多这些表达式的运算符。表达式 是 JavaScript 的短语&#xff0c;可以 评估 以产生一个值。在程序中直接嵌入的常量是一种非常简单的表达式。变量名也是一个简单表达式&#xff0c;它评估为分配给该变…

2024 Mazing 3 中文版新功能介绍Windows and macOS

iMazing 3中文版(ios设备管理软件)是一款管理苹果设备的软件&#xff0c; Windows 平台上的一款帮助用户管理 IOS 手机的应用程序。iMazing中文版与苹果设备连接后&#xff0c;可以轻松传输文件&#xff0c;浏览保存信息等&#xff0c;软件功能非常强大&#xff0c;界面简洁明晰…

【运维】MacOS Wifi热点设置

目录 打开热点 配置共享网段 打开热点 打开macOS设置&#xff0c;进入通用->共享 点击如下图标进行配置&#xff0c; 会进入如下界面&#xff08;⚠️目前是打开共享状态&#xff0c;无法修改配置&#xff0c;只有在未打开状态才能进入配置&#xff09; 配置完成后&#x…

2024.3.23

具体是哪些参数 每个点是如何投票的 删除那里不懂 是先给了&#xff0c;再重新分组&#xff0c;具体怎么再重新分组 聚的簇 真实的标签 为什么没有PI 加上其他的 基因调控网络

【前端寻宝之路】学习和总结有无序列表的实现和样式修改

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-WuZk6y8cqVpDsE8W {font-family:"trebuchet ms",verdana,arial,sans-serif;f…