【算法挨揍日记】day33——1027. 最长等差数列、446. 等差数列划分 II - 子序列

news2024/11/17 19:29:58

1027. 最长等差数列 

1027. 最长等差数列

题目描述:

给你一个整数数组 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. 状态表⽰:
对于线性 dp ,我们可以⽤「经验 + 题⽬要求」来定义状态表⽰:
i. 以某个位置为结尾,巴拉巴拉;
ii. 以某个位置为起点,巴拉巴拉。
这⾥我们选择⽐较常⽤的⽅式,以某个位置为结尾,结合题⽬要求,定义⼀个状态表⽰:
dp[i] 表⽰:以 i 位置元素为结尾的「所有⼦序列」中,最⻓的等差序列的⻓度。
但是这⾥有⼀个⾮常致命的问题,那就是我们⽆法确定 i 结尾的等差序列的样⼦。这样就会导致
我们⽆法推导状态转移⽅程,因此我们定义的状态表⽰需要能够确定⼀个等差序列。
根据等差序列的特性,我们仅需知道序列⾥⾯的最后两个元素,就可以确定这个序列的样⼦。因
此,我们修改我们的状态表⽰为:
dp[i][j] 表⽰:以 i 位置以及 j 位置的元素为结尾的所有的⼦序列中,最⻓的等差序列的
⻓度。规定⼀下 i < j
2. 状态转移⽅程:
nums[i] = b, nums[j] = c ,那么这个序列的前⼀个元素就是 a = 2 * b - c 。我们
根据 a 的情况讨论:
a. a 存在,下标为 k ,并且 a < b :此时我们需要以 k 位置以及 i 位置元素为结尾的最
⻓等差序列的⻓度,然后再加上 j 位置的元素即可。于是 dp[i][j] = dp[k][i] +
1 。这⾥因为会有许多个 k ,我们仅需离 i 最近的 k 即可。因此任何最⻓的都可以以 k
为结尾;
b. a 存在,但是 b < a < c :此时只能两个元素⾃⼰玩了, dp[i][j] = 2
c. a 不存在:此时依旧只能两个元素⾃⼰玩了, dp[i][j] = 2
综上,状态转移⽅程分情况讨论即可。
优化点:我们发现,在状态转移⽅程中,我们需要确定 a 元素的下标。因此我们可以将所有的元素 +
下标绑定在⼀起,放到哈希表中,这⾥有两种策略:
a. dp 之前,放⼊哈希表中。这是可以的,但是需要将下标形成⼀个数组放进哈希表中。这样
时间复杂度较⾼,我帮⼤家试过了,超时。
b. ⼀边 dp ,⼀边保存。这种⽅式,我们仅需保存最近的元素的下标,不⽤保存下标数组。但是
⽤这种⽅法的话,我们在遍历顺序那⾥,先固定倒数第⼆个数,再遍历倒数第⼀个数。这样就
可以在 i 使⽤完时候,将 nums[i] 扔到哈希表中。
3. 初始化:
根据实际情况,可以将所有位置初始化为 2
4. 填表顺序:
a. 先固定倒数第⼆个数;
b. 然后枚举倒数第⼀个数。
5. 返回值:
由于不知道最⻓的结尾在哪⾥,因此返回 dp 表中的最⼤值。

解题代码:

class Solution {
public:
    int longestArithSeqLength(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>dp(n,vector<int>(n,2));
        unordered_map<int,int>hash;
        int ret=2;
        hash[nums[0]]=0;
        for(int i=1;i<n-1;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                int a=2*nums[i]-nums[j];
                // int k=hash.count(a);
                if(hash.count(a))
                {
                    dp[i][j]=dp[hash[a]][i]+1;
                }
                ret=max(ret,dp[i][j]);
            }
                hash[nums[i]]=i;
        }
        return ret;
    }
};

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

题目描述:

给你一个整数数组 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. 状态表⽰:
对于线性 dp ,我们可以⽤「经验 + 题⽬要求」来定义状态表⽰:
i. 以某个位置为结尾,巴拉巴拉;
ii. 以某个位置为起点,巴拉巴拉。
这⾥我们选择⽐较常⽤的⽅式,以某个位置为结尾,结合题⽬要求,定义⼀个状态表⽰:
dp[i] 表⽰:以 i 位置元素为结尾的「所有⼦序列」中,等差⼦序列的个数。
但是这⾥有⼀个⾮常致命的问题,那就是我们⽆法确定 i 结尾的等差序列的样⼦。这样就会导致
我们⽆法推导状态转移⽅程,因此我们定义的状态表⽰需要能够确定⼀个等差序列。
根据等差序列的特性,我们仅需知道序列⾥⾯的最后两个元素,就可以确定这个序列的样⼦。因
此,我们修改我们的状态表⽰为:
dp[i][j] 表⽰:以 i 位置以及 j 位置的元素为结尾的所有的⼦序列中,等差⼦序列的个
数。规定⼀下 i < j
2. 状态转移⽅程:
nums[i] = b, nums[j] = c ,那么这个序列的前⼀个元素就是 a = 2 * b - c 。我们
根据 a 的情况讨论:
a. a 存在,下标为 k ,并且 a < b :此时我们知道以 k 元素以及 i 元素结尾的等差序列
的个数 dp[k][i] ,在这些⼦序列的后⾯加上 j 位置的元素依旧是等差序列。但是这⾥会多
出来⼀个以 k, i, j 位置的元素组成的新的等差序列,因此 dp[i][j] = dp[k][i]
+ 1
b. 因为 a 可能有很多个,我们需要全部累加起来。
综上, dp[i][j] += dp[k][i] + 1
优化点:我们发现,在状态转移⽅程中,我们需要确定 a 元素的下标。因此我们可以在 dp 之前,将
所有元素 + 下标数组绑定在⼀起,放到哈希表中。这⾥为何要保存下标数组,是因为我们要统计个
数,所有的下标都需要统计。
3. 初始化:
刚开始是没有等差数列的,因此初始化 dp 表为 0
4. 填表顺序:
a. 先固定倒数第⼀个数;
b. 然后枚举倒数第⼆个数。
5. 返回值:
我们要统计所有的等差⼦序列,因此返回 dp 表中所有元素的和。

 解题代码:

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>dp(n,vector(n,0));
        unordered_map<long long,vector<int>>hash;
        hash[nums[0]].push_back(0);
        int sum=0;
        for(int i=1;i<n-1;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                long long a=2*(long long)nums[i]-nums[j];
                if(hash.count(a))
                {
                    int length=hash[a].size();
                    for(int k=0;k<length;k++)
                    {
                        dp[i][j]+=dp[hash[a][k]][i]+1;
                    }
                }
                sum+=dp[i][j];
            }
            hash[nums[i]].push_back(i);
        }
        return sum;
    }
};

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

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

相关文章

两个链表的第一个公共节点(相交链表),剑指offer,力扣

目录 题目地址&#xff1a; 题目&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 审题目事例提示&#xff1a; 解题思路&#xff08;双指针&#xff09;&#xff1a; 具体思路流程&#xff1a; 代码实现&#xff1a; 算法思路补充证明&#xff1a; 力扣题目地…

Doris中的物化视图-查询(十九)

物化视图创建完成后&#xff0c;用户的查询会根据规则自动匹配到最优的物化视图。 比如我们有一张销售记录明细表&#xff0c;并且在这个明细表上创建了三张物化视图。一个存储了不同时间不同销售员的售卖量&#xff0c;一个存储了不同时间不同门店的销售量&#xff0c;以及每…

图数据库HugeGraph:HugeGraph-Hubble基于Web的可视化图管理初体验

原创/朱季谦 一、HugeGraph-Hubble简介 关于HugeGraph&#xff0c;官方资料是这样介绍的&#xff0c;它是一款易用、高效、通用的开源图数据库系统&#xff08;Graph Database&#xff09;&#xff0c; 实现了 Apache TinkerPop3 框架及完全兼容 Gremlin 查询语言&#xff0c…

2023.11.23 云服务器实现 Spring Boot 项目文件上传并访问

环境介绍 云服务器&#xff1a;京东云云服务器系统&#xff1a; CentOS 7.9JDK 版本&#xff1a;1.8Spring Boot 版本&#xff1a;2.7.17 具体步骤 步骤一 首先我们得先创建一个 Spring Boot 项目 创建如下目录结构 关于如何创建一个 Spring Boot 项目 请点击下方链接详细了解 …

vs2015如何远程启动程序来进行调试

vs远程调试的方式有两种&#xff0c;远程启动方式和附加进程方式。   一般来说&#xff0c;咱们使用vs调试代码时&#xff0c;直接附加进程即可&#xff0c;但某些时候附加进程方式无法命中断点。比如我们想调试的C代码&#xff0c;但是调试的入口程序是C#程序&#xff0c;如…

JavaScript实现动态背景颜色

JavaScript实现动态背景颜色 前言实现过程HTML实现过程CSS实现过程JS实现过程全部源码 前言 本文主要讲解JavaScript如何实现动态背景颜色&#xff0c;可以根据颜色选择器选择的颜色而实时更新到背景中&#xff0c;如下图所示。 当我们在颜色选择器中改变颜色时&#xff0c;会…

2023年10月纸巾市场分析(京东天猫淘宝平台纸巾品类数据采集)

双十一大促期间&#xff0c;刚需品的纸巾是必囤商品之一。今年双十一&#xff0c;京东数据显示&#xff0c;10月23日至29日&#xff0c;清洁纸品成交额同比增长40%&#xff0c;由此也拉动了10月纸巾市场的销售。 鲸参谋数据显示&#xff0c;今年10月&#xff0c;京东平台纸巾市…

Django JSONField/HStoreField SQL注入漏洞(CVE-2019-14234)

漏洞描述 Django 于2019年8月1日 日发布了安全更新&#xff0c;修复了 JSONField 和 HStoreField 两个模型字段的 SQL 注入漏洞。 参考链接&#xff1a; Django security releases issued: 2.2.4, 2.1.11 and 1.11.23 | Weblog | DjangoDjango JSONField SQL注入漏洞&#x…

java设计模式学习之【工厂模式】

文章目录 引言工厂方法模式简介定义与用途&#xff1a;实现方式&#xff1a; 使用场景优势与劣势工厂模式在spring中的应用电费计算示例&#xff08;简单工厂模式&#xff09;改善为方法工厂模式代码地址 引言 在软件开发的世界中&#xff0c;对象的创建可能是一个复杂且重复的…

NX二次开发UF_CSYS_edit_matrix_of_object 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CSYS_edit_matrix_of_object Defined in: uf_csys.h int UF_CSYS_edit_matrix_of_object(tag_t object_id, tag_t matrix_id ) overview 概述 Updates the specified coordinat…

杰发科技AC7801——ADC简单理解

前言 7801资料读起来不是很好理解&#xff0c;大概率是之前MTK的大佬写的。在此以简单的方式进行描述。我们做一个简单的规则组软件触发Demo。因为规则组通道只有一个数据寄存器&#xff0c;因此还需要用上DMA方式搬运数据到内存。 AC7801的ADC简介 7801的ADC是一种 12 位 逐…

7-22 龟兔赛跑

import java.util.Scanner; class Main {public static void main(String[] args) {Scanner scnew Scanner(System.in);int timesc.nextInt();sc.close();int wugui 0;//乌龟里程int tuzi 0;//兔子里程int tuzi_run0;int tuzi_rest0;int is_rest0;//是否需要休息&#xff1a;…

Python大语言模型实战-记录一次用ChatDev框架实现爬虫任务的完整过程

1、模型选择&#xff1a;GPT4 2、需求&#xff1a;在win10操作系统环境下&#xff0c;基于python3.10解释器&#xff0c;爬取豆瓣电影Top250的相关信息&#xff0c;包括电影详情链接&#xff0c;图片链接&#xff0c;影片中文名&#xff0c;影片外国名&#xff0c;评分&#x…

游戏是第一生产力!Python实现生命游戏的示例代码(tkinter版)

文章目录 生命游戏(Game of Life)游戏概述生存定律图形结构 代码实现运行界面使用简介后续改进关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五…

【Linux】匿名管道+进程池

文章目录 前置知识一、管道的原理二、管道的特性三、管道的接口四、使用管道实现简单的进程池解决进程池的一个小问题 前置知识 一个进程在创建时&#xff0c;会默认打开三个文件&#xff0c;分别是&#xff1a;stdin&#xff0c;stdout&#xff0c;stderr 进程中有一个维护进…

社区物联网云服务架构设计

文章目录 1 摘要2 架构图2.1 社区物联网云服务网络拓扑图2.2 社区物联网云服务通讯流程图2.3 社区远程开锁功能流程图 3 应用场景 1 摘要 随着社区管理越来越智能化&#xff0c;社区物联网升级与改造的市场空间也越来越大。社区物联网包含楼宇对讲、门禁门锁、通道闸等等设备系…

浅谈国内智能制造现状和未来发展趋势

进人二十一世纪&#xff0c;互联网、新能源、大数据等技术的迅猛发展&#xff0c;从而使得社会发生巨大的改变&#xff0c;人类生产工业发生变革。为应对全球挑战&#xff0c;我国根据发展的实际情况&#xff0c;提出《中国制造2025》的国家战略规划。毋庸置疑的是&#xff0c;…

大数据题目的解题技巧

目录 大数据题目的技巧总括 实例精析 实例一 实例二 实例三 大数据题目的技巧总括 &#xff08;1&#xff09;哈希函数可以把数据按照种类均匀分流&#xff1b; &#xff08;2&#xff09;布隆过滤器用于集合的建立与查询&#xff0c;并可以节省大量空间&#xff1b; &…

Git永久或者限时保存用户名及密码,解决每次拉取或者提交代码时都需要手动输入验证信息

介绍 这里以我自身项目情况为例: 依据项目要求,这边使用了 TortoiseGit进行项目的统一管理,下载了 TortoiseGit克隆项目之后,每次拉取或者提交代码,都会弹出一个提示框,要求输入用户名及密码。 解决方式 单个仓库内设置,只作用于对当前仓库 在当前项目目录文件夹下,…

vue3之echarts渐变柱状图

vue3之echarts渐变柱状图 效果&#xff1a; 核心代码&#xff1a; <template><div class"abnormal"><div class"chart" ref"chartsRef"></div></div> </template><script setup> import * as echa…