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

news2024/9/27 12:10:25

💕"你可以说我贱,但你不能说我的爱贱。"💕
作者: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];

        // 初始化为2
        for(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];

        // 初始化为2
        for(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.coloradmin.cn/o/1538902.html

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

相关文章

uni-app打包证书android

Android平台打包发布apk应用&#xff0c;需要使用数字证书&#xff08;.keystore文件&#xff09;进行签名&#xff0c;用于表明开发者身份。 Android证书的生成是自助和免费的&#xff0c;不需要审批或付费。 可以使用JRE环境中的keytool命令生成。 以下是windows平台生成证…

springboot实现文件上传

SpringBoot默认静态资源访问方式 首先想到的就是可以通过SpringBoot通常访问静态资源的方式&#xff0c;当访问&#xff1a;项目根路径 / 静态文件名时&#xff0c;SpringBoot会依次去类路径下的四个静态资源目录下查找&#xff08;默认配置&#xff09;。 在资源文件resour…

极大提高工作效率的 Linux 命令

作为一名软件开发人员&#xff0c;掌握 Linux 命令是必不可少的技能。即使你使用 Windows 或 macOS&#xff0c;你总会遇到需要使用 Linux 命令的场合。例如&#xff0c;大多数 Docker 镜像都基于 Linux 系统。要进行 DevOps 工作&#xff0c;你需要熟悉Linux&#xff0c;至少要…

Redis中的缓存穿透

缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;导致这些请求直接到了数据库上&#xff0c;对数据库造成了巨大的压力&#xff0c;可能造成数据库宕机。 常见的解决方案&#xff1a; 1&#xff09;缓存无效 key 如果缓存和数据库中都查不到某…

【漏洞复现】WordPress Plugin NotificationX 存在sql注入CVE-2024-1698

漏洞描述 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 WordPress Plugin NotificationX 存在安全漏洞,该漏洞源于对用户提供的…

校招免费资料大集合

通过以下资料&#xff0c;你可以免费获取到大量的校招资料和相关信息&#xff0c;帮助你更好地准备校园招聘。 学习交流群&#xff1a;进行计算机知识分享和交流&#xff0c;提供内推机会&#xff0c;QQ群号&#xff1a;325280438 夏沫Coding&#xff1a;致力于分享计算机干货…

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

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

AIGC:让生成式AI成为自己的外脑

前言 在数字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到了我们生活的方方面面。其中&#xff0c;生成式AI以其独特的魅力&#xff0c;正逐渐改变我们与世界的交互方式。AIGC&#xff08;人工智能生成内容&#xff09;作为生成式AI的重要应用…

LeetCode 热题 100 | 堆(二)

目录 1 什么是优先队列 1.1 优先队列与堆的关系 1.2 如何定义优先队列 1.3 如何使用优先队列 1.4 如何设置排序规则 2 347. 前 K 个高频元素 2.1 第 2 步的具体实现 2.2 举例说明 2.3 完整代码 3 215. 数组中的第 K 个最大元素 - v2 菜鸟做题&#xff0c;语…

cesium Clock JulianDate 日照分析

cesium在初始化的时候会自动把Clock对象挂载到容器上Clock内部以JulianDate维护时间&#xff0c;比北京时间慢8个小时&#xff0c;想显示北京时间需要计算时差JulianDate的日期部分和秒数部分是分开的 julianDayNumber&#xff1a;指整数天&#xff0c;记录从公元前4713年正午以…

基于SpringBoot实现WebSocket实时通讯的服务端和客户端

实现功能 服务端注册的客户端的列表&#xff1b;服务端向客户端发送广播消息&#xff1b;服务端向指定客户端发送消息&#xff1b;服务端向多个客户端发送消息&#xff1b;客户端给服务端发送消息&#xff1b; 效果&#xff1a; 环境 jdk&#xff1a;1.8 SpringBoot&#x…

社区热议!54.8k Star开源项目,GPT-4Free : 让GPT4免费不是梦

Hello&#xff0c;我是Aitrainee&#xff0c;GPT4Free就是最近传得沸沸扬扬的那个GPT4项目。大家都知道&#xff0c;虽然ChatGPT是免费的&#xff0c;但如果你想用到那些功能更强大的大模型&#xff0c;比如GPT-4、gemini-pro、claude&#xff0c;那就只能选择付费了。 但现在&…

在Linux搭建Emlog博客结合内网穿透实现公网访问本地个人网站

文章目录 前言1. 网站搭建1.1 Emolog网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总结 前言 博客作为使…

【2024最新版,redis7】redis底层的10种数据结构

前言&#xff1a;本文redis版本&#xff1a;7.2.4 本文语雀原文地址&#xff08;首发更新&#xff09;&#xff1a;https://www.yuque.com/wzzz/redis/xg2cp37kx1s4726y 本文CSDN转载地址&#xff1a; https://blog.csdn.net/u013625306/article/details/136842107 1. 常见的数…

烯冷新能源邀您参观2024长三角快递物流展

参加企业介绍 宁波戈雷贝拓科技有限公司&#xff08;宁波烯冷新能源科技有限公司&#xff09;宁波烯冷新能源科技有限公司于2022年初成立&#xff0c;依托中国科学院宁波材料技术与工程研究所和国家石墨烯创新中心&#xff0c;公司开发产品包括&#xff1a;新能源制冷系统和集…

Mysql学习--深入探究索引和事务的重点要点与考点

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

一键入门Ubuntu22!

目录 一、安装 二、常用目录 三、常用指令 四、用户指令 五、ssh与scp 六、服务相关 七、Python与Pycharm 八、Vim编辑器 九、Ubuntu22下使用Mysql 十、Ubuntu22下使用mongodb 十一、Ubuntu22下使用redis Ubuntu是一个基于Debian的开源操作系统&#xff0c;由Canoni…

LeetCode每日一题——x 的平方根

x 的平方根OJ链接&#xff1a;69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 思路&#xff1a; 乍一看题目只需要算一个数的平方根&#xff0c;根据我们之前学的C语言我们能很快的想到使用sqrt&#xff0c;pow这类的<math.h>库函数&#xf…

【计算机网络篇】数据链路层(2)封装成帧和透明传输

文章目录 &#x1f95a;封装成帧和透明传输&#x1f388;封装成帧&#x1f388;透明传输&#x1f5d2;️面向字节的物理链路使用字节填充的方法实现透明传输。&#x1f5d2;️面向比特的物理链路使用比特填充的方法实现透明传输。 &#x1f6f8;练习 &#x1f95a;封装成帧和透…

【目标检测基础篇】目标检测评价指标:mAP计算的超详细举例分析以及coco数据集标准详解(AP/AP50/APsmall.....))

学习视频&#xff1a; 霹雳吧啦Wz-目标检测mAP计算以及coco评价标准 【目标检测】指标介绍&#xff1a;mAP 1 TP/FP/FN TP(True Positive) : IoU>0.5的检测框数量(同一Ground truth只计算一次)FP(False Positive) : IoU<0.5的检测框(或者是检测到同一个GT的多余检测框的…