动态规划-子序列问题2

文章目录

  • 1. 最长定差子序列(1218)
  • 2. 最长的斐波那契子序列的长度(873)
  • 3. 最长等差数列(1027)
  • 4. 等差数列划分 II - 子序列(446)


1. 最长定差子序列(1218)

题目描述:
在这里插入图片描述

状态表示:
根据题目要求以及做题经验可以设置一个数组dp,将dp[i]表示为以arr数组的i位置为结尾的等差子序列的最大长度。
状态转移方程:
这题在子序列问题中算是经典的一个问题,状态转移方程就是在dp[i]-dp[j]==difference时,dp[i[=dp[j]+1,这里的j就是从0~i-1的一个值,用于在i的循环中加上一个循环来遍历子序列的多种可能。具体可以看代码,逻辑相对简单。
初始化:
初始化还是一样,因为子序列的长度都是至少为1,所以先将dp数组的所有元素赋为1。
填表顺序:
从左至右。
返回值:
dp数组中的最大值。
代码如下:

class Solution {public int longestSubsequence(int[] arr, int difference) {int n = arr.length;int[] dp = new int[n];for (int i = 0; i < n; i++) {dp[i] = 1;}int max = 1;for (int i = 1; i < n; i++) {for (int j = i - 1; j >= 0; j--) {if (arr[i] - arr[j] == difference) {dp[i] = dp[j] + 1;break;}}max = Math.max(max, dp[i]);}return max;}
}

优化:
理论上以上的代码可以解决上述问题,但是在leetcode的提交过程中出现提交超时的情况,所以可以使用另一种思想来编写代码。直接遍历一遍arr数组来完成动态规划。

class Solution {public int longestSubsequence(int[] arr, int difference) {Map<Integer, Integer> hash = new HashMap<>();int ret = 1;for (int n : arr) {hash.put(n, hash.getOrDefault(n - difference, 0) + 1);ret = Math.max(ret, hash.get(n));}return ret;}
}

要理解上述代码的意思,就得先理解第一段代码中的一个点,那就是对于i位置,要得到最长的等差子序列的长度不需要去遍历i位置前的每一个元素,只需要去遍历到第一个满足条件的j下标即可,因为后面的子序列长度不可能会超过j’位置的长度。
优化后的代码就使用到了这种思想,使用了哈希来存对应的数值对,遍历arr,对于每个值a存入(a,满足以a为结尾的等差子序列最大长度),当然这里()中的第二个值有几种特殊情况,第一种例如a是第一个数,那么肯定构不成等差子序列第二项就赋为1。第二种情况,对于a-difference,在哈希表中搜索不到这样的值,因为我们遍历数组是从前往后遍历的,所以这种情况就说明了对于a没有满足条件的等差子序列,那么a对应的第二项就是赋为1。在正常情况下,就是a-difference能在哈希表中搜索到,那么就将a对应的第二个值赋为a-difference在哈希表中对应的第二个值+1。
有人可能会问,为什么使用a-difference对应的第二值更新的a对应的第二值就是最大的值,因为我们是从前往后遍历arr的,然后hash中的特性就是当key相同时会将对应的value值赋为后续加入的key对应的value,因为后续加入的a-difference对应的value肯定比前面的a-difference的value大,也就是后续加入的a-difference对应的等差子序列的长度肯定比前面的a-difference的等差子序列大,所以这样更新值自然正确。

题目链接

优化后时间复杂度:O(N)
优化后空间复杂度:O(N)

2. 最长的斐波那契子序列的长度(873)

题目描述:
在这里插入图片描述

状态表示:
这题的状态表示比较特殊,因为单独使用dp[i]无法解题,因为使用二位数组进行状态表示,设置dp[i][j]为以arr数组中的i和j元素为结尾时的最长的斐波那契子序列的长度。
状态转移方程:
状态转移方程和前面做过的子序列问题还是相似的,就是两层的循环再去寻找满足条件的第三个元素,这里的条件就是斐波那契数列的条件,当元素存在并且在arr数组中的下标为k时,那么dp[i][j]=dp[k][i]+1。
初始化:
初始化的话,因为固定住了两个尾部元素所以长度至少是为2的,所以直接将dp这个二维数组的每个元素都赋为2。但是如果最终数组中是没有斐波那契数列的话,那么就不能返回2,因为题目要求只能要么返回大于等于3这种有斐波那契子序列的情况,要么返回0,所以在返回结果那里要多加一个判断。前面我们将dp数组全赋为2单纯是为了计算。
填表顺序:
从上到下,从左至右。
代码如下:

class Solution {public int lenLongestFibSubseq(int[] arr) {int n = arr.length;int[][] dp = new int[n][n];Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i < n; i++) {map.put(arr[i], i);}for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {dp[i][j] = 2;}}int ret = 2;for (int j = 2; j < n; j++) {for (int i = 1; i < j; i++) {int temp = arr[j] - arr[i];if (map.containsKey(temp) && temp < arr[i]) {dp[i][j] = dp[map.get(temp)][i] + 1;}ret = Math.max(ret, dp[i][j]);}}return ret == 2 ? 0 : ret;}
}

题目链接
时间复杂度:O(N^2)
空间复杂度:O(N^2)

3. 最长等差数列(1027)

题目描述:
在这里插入图片描述

状态表示:
根据上一题的经验,我们就可以设置二维数组dp,并且使用dp[i][j]来表示以i,j位置元素为结尾的最长等差子序列。
状态转移方程:
状态转移方程也是类似的,就是先固定住后两个元素位置,然后搜寻是否有满足等差数列的第一个元素,如果有则dp[i][j]=dp[k][i]+1,但是这里要注意一点,因为本题给的nums数组不是严格递增,所以可能会出现多种情况,所以不能直接一次性将nums送到map中。为了避免nums中的值相同等问题,可以先固定住下标i,然后递增j,然后先仅仅向map中添加i位置之前元素的数对,因为此时的dp[i][j]的运算只涉及到这些,通过这种方法可以有效处理问题。
初始化:
初始化也是一样将二维数组中的所有值赋为2。
填表顺序:
从上到下,从左至右。
代码如下:

class Solution {public int longestArithSeqLength(int[] nums) {int n = nums.length;int[][] dp = new int[n][n];for (int i = 0; i < n; i++) {Arrays.fill(dp[i], 2);}Map<Integer, Integer> map = new HashMap<>();map.put(nums[0], 0);int ret = 2;for (int i = 1; i < n; i++) {for (int j = i + 1; j < n; j++) {int temp = 2 * nums[i] - nums[j];if (map.containsKey(temp)) {dp[i][j] = dp[map.get(temp)][i] + 1;ret = Math.max(ret, dp[i][j]);}}map.put(nums[i], i);}return ret;}}

题目链接
时间复杂度:O(N^2)
空间复杂度:O(N^2)

4. 等差数列划分 II - 子序列(446)

题目描述:
在这里插入图片描述

状态表示:
根据前几题的经验,设置二维数组dp[i][j]为以i和j位置元素为结尾时的等差子序列的个数。
状态转移方程:
状态转移方程还是类似的思想,使用两层循环固定住后两个元素的下标然后去寻找满足条件的第一个元素。如果满足条件那么dp[i][j]+=dp[k][i]。不过要注意一个点,就是因为这里是计算等差子序列的个数,所以所有满足条件的第一个元素都要加上。代码中的实现就是,使用哈希表来记录同意数值的不同下标,这样在循环中对于满足条件并且下标小于i的dp值就可以直接加上。具体看代码。
初始化:
初始化因为两个元素无法构成题目要求的等差子序列,所以dp数组全赋为0即可。
填表顺序:
从左至右,从上到下。
返回值:
返回dp数组中的值的和(部分经过处理的和)。
代码如下:

public int numberOfArithmeticSlices(int[] nums) {int n = nums.length;Map<Integer, List<Integer>> map = new HashMap<>();for (int i = 0; i < n; i++) {int temp = nums[i];if (!map.containsKey(temp)) {map.put(temp, new ArrayList<Integer>());}map.get(temp).add(i);}int[][] dp = new int[n][n];int sum = 0;for (int j = 2; j < n; j++) {for (int i = 1; i < j; i++) {int temp = 2 * nums[i] - nums[j];if (map.containsKey(temp)) {for (int a :map.get(temp)) {if (a < i) {dp[i][j] += dp[a][i];}}}sum += dp[i][j];}}return sum;}

题目链接
时间复杂度:O(N^2)
空间复杂度:O(N^2)

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

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

相关文章

制定语音芯片的语音识别指令时需要关注的内容

背景 最近定义设备识别的语音指令以及对应的语音反馈。虽然语音控制在软件里只是很小的一块功能&#xff0c;但也不能太马虎。新人入坑就要学习&#xff0c;学习前人的经验规避问题&#xff0c;最后总结经验给后人&#xff0c;给未来的自己。好记性不如烂笔头~ 下面一些问题是…

1天搞定uniApp+Vue3+vite+Element UI或者Element Plus开发学习,使用vite构建管理项目,HBuilderX做为开发者工具

我们通常给小程序或者app开发后台时&#xff0c;不可避免的要用到可视化的数据管理后台&#xff0c;而vue和Element是我们目前比较主流的开发管理后台的主流搭配。所以今天石头哥就带大家来一起学习下vue3和Element plus的开发。 准备工作 1&#xff0c;下载HBuilderX 开发者…

Ansys Speos|进行智能手机镜头杂散光分析

本例的目的是研究智能手机Camera系统的杂散光。杂散光是指光向相机传感器不需要的散光光或镜面光&#xff0c;是在光学设计中无意产生的&#xff0c;会降低相机系统的光学性能。 在本例中&#xff0c;光学透镜系统使用Ansys Zemax OpticStudio (ZOS)进行设计&#xff0c;并使用…

【Jenkins】持续集成与交付 (四):修改Jenkins插件下载地址、汉化

🟣【Jenkins】持续集成与交付 (四):修改Jenkins插件下载地址、汉化 一、修改Jenkins插件下载地址二、汉化Jenkins三、关于Jenkins💖The Begin💖点点关注,收藏不迷路💖 一、修改Jenkins插件下载地址 由于Jenkins官方插件地址下载速度较慢,我们可以通过修改下载地址…

卫星通信现状与展望三 -- 6G

作者:私语茶馆 6G星地一体远景规划 中国信通院《6G总体远景与潜在关键技术白皮书》指出6G将实现地面网络、不同轨道高度上 的卫星(高中低轨卫星)以及不同空域飞行器等融合而成全新的移动信息网络,通过地面网络实现城市热点常态化覆盖,利用天基、空基网络实现偏远地…

企业家必须提升演讲口才的原因(3篇)

企业家必须提升演讲口才的原因&#xff08;3篇&#xff09; **篇&#xff1a;企业家必须提升演讲口才的原因——建立品牌影响力 一、引言 在当今竞争激烈的市场环境中&#xff0c;企业家作为企业的灵魂和代表&#xff0c;其个人形象和品牌影响力对于企业的成功至关重要。而演…

特征提取(Feature Extraction)常见统计特征笔记(三)

统计特征是描述数据集中值的一组量&#xff0c;通常用于了解数据的分布、集中趋势和变异程度。常见的统计特征包括均值、中位数、众数、标准差、方差等。下面会详细解释每个统计特征&#xff0c;并给出相应的Python代码。 1、均值&#xff08;Mean&#xff09;&#xff1a;所有…

中兴UME网管LTE共享参数配置-PLMN添加

本文为中兴设备UME网管电联中频共享参数配置&#xff0c;PLMN添加参数配置部分&#xff0c;因UME与U&#xff13;&#xff11;网管添加PLMN配置区别较大&#xff0c;UME网管需同时配置运营商EN&#xff0d;DC策略&#xff0c;相关配置流程及参数配置如下文。 PLMN eNodeB CU …

前后端数据加密代码实战(vue3.4+springboot 2.7.18)

简述&#xff1a; 文章主要讲述了在vue3与springboot交互数据的个人使用的一个加密形式 SHA256不可逆加密AES对称加密RSA非对称加密 加密算法就不带大家深入了&#xff0c;对于它的使用文章中有明确的案例 数据加密的大概流程为&#xff1a;&#xff08;有更优秀的方案可以…

OpenCV 实现霍夫圆变换(52)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV实现霍夫变换(51) 下一篇:OpenCV 实现重新映射(50) 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 HoughCircles()检测图像中的圆圈。 理论 Hough 圆…

KPlayer搭建指南:开启24小时直播之旅

引言 在这个数字化时代&#xff0c;无人值守直播成为了一种新兴的趋势。无论是企业还是个人&#xff0c;都可以通过无人值守直播来提高效率和观众参与度。本文将介绍如何使用KPlayer在Linux环境下搭建无人值守直播系统。 KPlayer简介 KPlayer是一款基于Linux的媒体服务器工具…

STM32利用硬件I2C读取MPU6050陀螺仪数据

有了前面的基本配置&#xff0c;这节读取MPU6050的数据还算是简单&#xff0c;主要就是初始化时给MPU6050一些配置&#xff0c;取消睡眠模式&#xff0c;MPU6050开机是默认睡眠模式的&#xff0c;读写无效&#xff0c;所以上来就要先更改配置&#xff1a; MPU6050寄存器初始化…