【动态规划刷题 16】最长等差数列 (有难度) 等差数列划分 II - 子序列

news2024/11/25 4:48:16

1027. 最长等差数列

https://leetcode.cn/problems/longest-arithmetic-subsequence/

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

回想一下,nums 的子序列是一个列表 nums[i1], nums[i2], …, nums[ik] ,且 0 <= i1 < i2 < … < ik <= nums.length - 1。并且如果 seq[i+1] - seq[i]( 0 <= i < seq.length - 1) 的值都相同,那么序列 seq 是等差的。

示例 1:

输入:nums = [3,6,9,12]
输出:4
解释:
整个数组是公差为 3 的等差数列。
示例 2:

输入:nums = [9,4,7,2,10]
输出:3
解释:
最长的等差子序列是 [4,7,10]。
示例 3:

输入:nums = [20,1,15,3,10,5,8]
输出:4
解释:
最长的等差子序列是 [20,15,10,5]。

1.状态表示*
我们先试着定义一个状态转移数组:
dp[i] 表⽰:以 i 位置元素为结尾的「所有⼦序列」中,最⻓的等差序列的⻓度。
但是这⾥有⼀个⾮常致命的问题,那就是我们⽆法确定 i 结尾的等差序列的样⼦。这样就会导致我们⽆法推导状态转移⽅程,因此我们定义的状态表⽰需要能够确定⼀个等差序列:
dp[i][j] 表⽰:以 i 位置以及 j 位置的元素为结尾的所有的⼦序列中,最⻓的等差序列的⻓度。

2.状态转移方程
设 nums[i] = b, nums[j] = c ,那么这个序列的前⼀个元素就是 a = 2 * b - c 。我们
根据 a 的情况讨论:

  1. a 存在,下标为 k ,并且 a < b :此时我们需要以 k 位置以及 i 位置元素为结尾的最⻓等差序列的⻓度,然后再加上 j 位置的元素即可。于是dp[i][j] = dp[k][i] +1 。这⾥因为会有许多个 k ,我们仅需离 i 最近的 k 即可。因此任何最⻓的都可以以 k 为结尾;
  2. a 存在,但是 b < a < c :此时只能两个元素⾃⼰玩了, dp[i][j] = 2 ;
  3. a 不存在:此时依旧只能两个元素⾃⼰玩了, dp[i][j] = 2 ;

优化:
⼀边 dp ,⼀边保存。这种⽅式,我们仅需保存最近的元素的下标,不⽤保存下标数组。但是⽤这种⽅法的话,我们在遍历顺序那⾥,先固定倒数第⼆个数,再遍历倒数第⼀个数。这样就可以在 i 使⽤完时候,将 nums[i] 扔到哈希表中。

3. 初始化
根据实际情况,可以将所有位置初始化为 2 。

4. 填表顺序
a. 先固定倒数第⼆个数;
b. 然后枚举倒数第⼀个数。

5. 返回值
由于不知道最⻓的结尾在哪⾥,因此返回 dp 表中的最⼤值。

代码:

 int longestArithSeqLength(vector<int>& nums) {
        int n=nums.size();
        unordered_map<int,int> hash;
        hash[nums[0]]=0;

        //表示的是以 i,j 为结尾的,最长的等差子序列的长度
        int Max=2;
        vector<vector<int>>  dp(n,vector<int>(n,2));
        for(int i=0;i<n;i++)//先固定倒数第二个位置
        {
            for(int j=i+1;j<n;j++)//在固定倒数第一个位置
            {
                int a=2*nums[i]-nums[j];
                if(hash.count(a)&&hash[a]<i)
                   dp[i][j]=dp[hash[a]][i]+1;

                 Max=max(Max,dp[i][j]);
            }
            hash[nums[i]]=i;
        }
        return Max;

    }

在这里插入图片描述

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

https://leetcode.cn/problems/arithmetic-slices-ii-subsequence/

给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。

如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。

例如,[1, 3, 5, 7, 9]、[7, 7, 7, 7] 和 [3, -1, -5, -9] 都是等差序列。
再例如,[1, 1, 2, 5, 7] 不是等差序列。
数组中的子序列是从数组中删除一些元素(也可能不删除)得到的一个序列。

例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。
题目数据保证答案是一个 32-bit 整数。

示例 1:

输入:nums = [2,4,6,8,10]
输出:7
解释:所有的等差子序列为:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]
示例 2:

输入:nums = [7,7,7,7,7]
输出:16
解释:数组中的任意子序列都是等差子序列。

1.状态表示*
我们先试着定义一个状态转移数组:
dp[i] 表⽰:以 i 位置元素为结尾的「所有⼦序列」中,最⻓的等差序列的⻓度。
但是这⾥有⼀个⾮常致命的问题,那就是我们⽆法确定 i 结尾的等差序列的样⼦。这样就会导致我们⽆法推导状态转移⽅程,因此我们定义的状态表⽰需要能够确定⼀个等差序列:
dp[i][j] 表⽰:以 i 位置以及 j 位置的元素为结尾的所有的⼦序列中,等差⼦序列的个数。

2.状态转移方程
设 nums[i] = b, nums[j] = c ,那么这个序列的前⼀个元素就是 a = 2 * b - c 。我们
根据 a 的情况讨论:

  1. a 存在,下标为 k ,并且 a < b :此时我们需要以 k 位置以及 i 位置元素为结尾的最⻓等差序列的⻓度,然后再加上 j 位置的元素即可。于是dp[i][j] = dp[k][i] +1 。这⾥因为会有许多个 k ,我们仅需离 i 最近的 k 即可。因此任何最⻓的都可以以 k 为结尾;
  2. b. 因为 a 可能有很多个,我们需要全部累加起来

综上, dp[i][j] += dp[k][i] + 1 。

优化:
优化点:我们发现,在状态转移⽅程中,我们需要确定 a 元素的下标。因此我们可以在 dp 之前,将
所有元素 +下标数组绑定在⼀起,放到哈希表中。这⾥为何要保存下标数组,是因为我们要统计个
数,所有的下标都需要统计。
3. 初始化
刚开始是没有等差数列的,因此初始化 dp 表为 0
4. 填表顺序
a. 先固定倒数第⼆个数;
b. 然后枚举倒数第⼀个数。

5. 返回值
我们要统计所有的等差⼦序列,因此返回 dp 表中所有元素的和。

代码:

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);
        }

        int sum=0;
        vector<vector<int>> dp(n,vector<int>(n));
        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 e:hash[a])
                        {
                            if(e<i) { dp[i][j]+=dp[e][i]+1;}
                            else break;
                        }
                }
                sum+=dp[i][j];
            }
        }
        return sum;

    }

在这里插入图片描述

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

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

相关文章

C++之浅拷贝、深拷贝、拷贝构造函数、拷贝赋值运算符、自定义的深拷贝函数应用总结(二百二十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

宝塔重装注意事项

欢迎关注我的公众号&#xff1a;夜说猫&#xff0c;让一个贫穷的程序员不靠打代码也能吃饭~ 前言 宝塔8.0版本&#xff0c;宝塔卸载重装&#xff0c;或者重装Linux系统后重新安装宝塔也适用。 不能上来直接就执行安装宝塔脚本&#xff0c;除非之前没有安装过宝塔。 步骤 1、…

短视频源码php

对于php短视频源码而言&#xff0c;视频质量与用户使用体验息息相关&#xff0c;高质量的视频观感更有利于留下用户。但实际上视频质量很容易受到各种因素的影响&#xff0c;接下来我们分析一下php短视频源码中导致视频出现异常的各种原因吧。 所谓短视频源码的原生开发&#…

华为云云耀云服务器L实例评测|华为云上安装kafka

文章目录 华为云云耀云服务器L实例评测&#xff5c;华为云上安装kafka一、kafka介绍二、华为云主机准备三、kafka安装1. 安装什么版本java2. 安装zookeeper服务3. 使用systemctl 管理启动ZooKeeper服务4. 修改kafka配置5. 使用systemctl 管理启动kafka服务6. 创建一个测试 topi…

Springboot 实践(21)服务熔断机制

在微服务架构中&#xff0c;服务众多&#xff0c;通常会涉及到多个服务层的调用&#xff0c;一旦基础服务发生故障&#xff0c;很可能会导致级联故障&#xff0c;继而造成整个系统不可用&#xff0c;这种现象被称为服务雪崩效应。 服务熔断引入熔断器概念&#xff0c;熔断器如果…

libopenssl 实现私钥加密公钥解密

在需要验证可信来源时&#xff0c;需要用到签名验签。因此&#xff0c;需要使用私钥加密&#xff0c;公钥解密&#xff0c;取得被加密的信息。这就会使用到私钥加密&#xff0c;公钥解密的场景了。 参考&#xff1a; https://github.com/openssl/openssl/issues/20493 https:/…

【Python】Pycharm使用anaconda中的PaddleOCR的虚拟环境 卡在loading package list(保姆级图文)

目录 异常表现&#xff1a;解决方法1. 试着使用pytcharm的http代理&#xff08;很确定没用&#xff0c;无法成功&#xff0c;直接看下一步&#xff09;2. conda换国内源&#xff08;换源后重启&#xff1f;不知道有没有用&#xff0c;不确定是否关键&#xff09;3. 在conda中更…

2023年浙工商MBA新生奖学金名单公布,如何看待?

浙工商MBA项目官方最新公布了2023年的非全日制新生奖学金名单&#xff0c;按照政策约定&#xff0c;共分为特等奖学金1名&#xff0c;一等奖学金10名&#xff0c;二等奖学金15名&#xff0c;三等奖学金30名&#xff0c;额度对应3万、1万、0.8万、0.5万不等&#xff0c;主要名单…

c++ 继承与多态

一、c如何解决菱形继承的问题 例子一 菱形继承问题 #include <iostream> #include <string.h> using namespace std; class Animal { public:int m_Age; }; class Sheep : public Animal {}; class Tuo : public Animal {}; class SheepTuo :public Sheep, publ…

phpstudy脚本编写 和sql注入编写

1.phpstudy编写 2.sql注入编写

一、iMove源码解读:初识

引言&#xff1a;随着低代码思想的不断蔓延&#xff0c;除了大企业&#xff0c;中小企业也尝试构建自己的低代码平台&#xff0c;以期降低开发门槛&#xff0c;提高开发效率&#xff0c;降低生产成本。本文中的iMove是一款面向前端开发者的逻辑编排工具&#xff0c;通过它设计出…

【Java 基础篇】Java线程安全与并发问题详解

多线程编程在Java中是一个常见的需求&#xff0c;它可以提高程序的性能和响应能力。然而&#xff0c;多线程编程也带来了一系列的线程安全与并发问题。在本文中&#xff0c;我们将深入探讨这些问题&#xff0c;以及如何解决它们&#xff0c;适用于Java初学者和基础用户。 什么…

机器学习入门教学——损失函数(交叉熵法)

1、前言 我们在训练神经网络时&#xff0c;最常用到的方法就是梯度下降法。在了解梯度下降法前&#xff0c;我们需要了解什么是损失(代价)函数。所谓求的梯度&#xff0c;就是损失函数的梯度。如果不知道什么是梯度下降的&#xff0c;可以看一下这篇文章&#xff1a;机器学习入…

人工智能的未来:技术与道德的交汇

人工智能的未来&#xff1a;技术与道德的交汇 摘要引言技术的前景1. 机器学习的进展2. 自主智能系统 道德考量3. 数据隐私与安全4. 自主决策的伦理 社会影响5. 就业与教育6. 医疗与健康 总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;…

新款 锐科达 SV-2402VP SIP广播音频模块 支持RTP流音频广播

新款 锐科达 SV-2402VP SIP广播音频模块 支持RTP流音频广播 SV-2402VP网络音频模块是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议和音频编解码协议&#xff0c;可用于VoI…

Spring底层原理之 BeanFactory 与 ApplicationContext

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Spring底层原理 一、 BeanFactory 与 Appli…

华为杯数学建模比赛经验分享第二期——编程手篇

数学建模比赛中编程手是较为重要的角色&#xff0c;不仅需要根据建模手的思路完成代码的编写&#xff0c;还需要与写作手沟通结果分析与呈现。 所以&#xff0c;编程手必须在不同的阶段完成相应的学习&#xff0c;这里我把它分为赛前和赛中。 1、赛前 在短短4天的学习新的代码…

虚拟DOM与diff算法

虚拟DOM与diff算法 snabbdom虚拟DOMdiff算法 snabbdom 是什么&#xff1a;snabbdom是著名的虚拟DOM库&#xff0c;是diff算法的鼻祖&#xff0c;Vue源码借鉴了snabbdom 虚拟DOM 是什么&#xff1a;本质上是存在内存里的 JavaScript 对象 作用&#xff1a;用来描述真实DOM的层…

DA2--获取网站用户数据集的大小

目录 1.题目描述 2.输入描述 3.输出描述 4.题目分析 5.通过代码 1.题目描述 现有一个Nowcoder.csv文件&#xff0c;它记录了牛客网的部分用户数据&#xff0c;包含如下字段&#xff08;字段与字段之间以逗号间隔&#xff09;&#xff1a; Nowcoder_ID&#xff1a;用户ID…

Vue 使用vue-cli构建SPA项目(超详细)

目录 一、什么是vue-cli 二&#xff0c;构建SPA项目 三、 运行SPA项目 前言&#xff1a; 在我们搭建SPA项目时候&#xff0c;我们必须去检查我们是否搭建好NodeJS环境 cmd窗口输入以下指令&#xff1a;去检查 node -v npm -v 一、什么是vue-cli Vue CLI&#xff08;Vu…