【算法挨揍日记】day27——152. 乘积最大子数组、1567. 乘积为正数的最长子数组长度

news2024/11/19 13:25:23

 152. 乘积最大子数组

152. 乘积最大子数组

题目描述:

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

子数组 是数组的连续子序列。

 解题思路:

这道题与「最⼤⼦数组和」⾮常相似,我们可以效仿着定义⼀下状态表⽰以及状态转移:
i. dp[i] 表⽰以 i 为结尾的所有⼦数组的最⼤乘积,
ii. dp[i] = max(nums[i], dp[i - 1] * nums[i])
由于正负号的存在,我们很容易就可以得到,这样求 dp[i] 的值是不正确的。因为 dp[i -
1] 的信息并不能让我们得到 dp[i] 的正确值。⽐如数组 [-2, 5, -2] ,⽤上述状态转移得
到的 dp数组为 [-2, 5, -2] ,最⼤乘积为 5 。但是实际上的最⼤乘积应该是所有数相乘,结
果为 20
究其原因,就是因为我们在求 dp[2] 的时候,因为 nums[2] 是⼀个负数,因此我们需要的是
i - 1 位置结尾的最⼩的乘积 ( -10 ) 」,这样⼀个负数乘以「最⼩值」,才会得到真实的
最⼤值。
因此,我们不仅需要⼀个「乘积最⼤值的 dp 表」,还需要⼀个「乘积最⼩值的 dp 表」。
1. 状态表⽰:
f[i] 表⽰:以 i 结尾的所有⼦数组的最⼤乘积,
g[i] 表⽰:以 i 结尾的所有⼦数组的最⼩乘积。
2. 状态转移⽅程:
遍历每⼀个位置的时候,我们要同步更新两个 dp 数组的值。
对于 f[i] ,也就是「以 i 为结尾的所有⼦数组的最⼤乘积」,对于所有⼦数组,可以分为下
⾯三种形式:
i. ⼦数组的⻓度为 1 ,也就是 nums[i]
ii. ⼦数组的⻓度⼤于 1 ,但 nums[i] > 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼤乘积 f[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * f[i - 1]
iii. ⼦数组的⻓度⼤于 1 ,但 nums[i] < 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼩乘积 g[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * g[i - 1]
(如果 nums[i] = 0 ,所有⼦数组的乘积均为 0 ,三种情况其实都包含了)
综上所述, f[i] = max(nums[i], max(nums[i] * f[i - 1], nums[i] * g[i -
1]) )。
对于 g[i] ,也就是「以 i 为结尾的所有⼦数组的最⼩乘积」,对于所有⼦数组,可以分为下
⾯三种形式:
i. ⼦数组的⻓度为 1 ,也就是 nums[i]
ii. ⼦数组的⻓度⼤于 1 ,但 nums[i] > 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼩乘积 g[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * g[i - 1]
iii. ⼦数组的⻓度⼤于 1 ,但 nums[i] < 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼤乘积 f[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * f[i - 1]
综上所述, g[i] = min(nums[i], min(nums[i] * f[i - 1], nums[i] * g[i -
1]))
(如果 nums[i] = 0 ,所有⼦数组的乘积均为 0 ,三种情况其实都包含了)
3. 初始化:
可以在最前⾯加上⼀个辅助结点,帮助我们初始化。使⽤这种技巧要注意两个点:
i. 辅助结点⾥⾯的值要保证后续填表是正确的;
ii. 下标的映射关系。
在本题中,最前⾯加上⼀个格⼦,并且让 f[0] = g[0] = 1 即可。
4. 填表顺序:
根据状态转移⽅程易得,填表顺序为「从左往右,两个表⼀起填」。
5. 返回值:
返回 f 表中的最⼤值。

解题代码:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n=nums.size();
        if(n==1)return nums[0];
        vector<int>f(n,0);
        vector<int>g(n,0);
        f[0]=nums[0];g[0]=nums[0];
        for(int i=1;i<n;i++)
        {
            f[i]=max(max(f[i-1]*nums[i],g[i-1]*nums[i]),nums[i]);
            g[i]=min(min(g[i-1]*nums[i],nums[i]*f[i-1]),nums[i]);
        }
        int ret=INT_MIN;
        for(int i=0;i<n;i++)ret=max(ret,f[i]);
        return ret;
        
    }
};

1567. 乘积为正数的最长子数组长度

1567. 乘积为正数的最长子数组长度

题目描述:

给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。

一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。

请你返回乘积为正数的最长子数组长度。

 解题思路:

算法思路:
继续效仿「最⼤⼦数组和」中的状态表⽰,尝试解决这个问题。
状态表⽰: dp[i] 表⽰「所有以 i 结尾的⼦数组,乘积为正数的最⻓⼦数组的⻓度」。
思考状态转移:对于 i 位置上的 nums[i] ,我们可以分三种情况讨论:
i. 如果 nums[i] = 0 ,那么所有以 i 为结尾的⼦数组的乘积都不可能是正数,此时
dp[i] = 0
ii. 如果 nums[i] > 0 ,那么直接找到 dp[i - 1] 的值(这⾥请再读⼀遍 dp[i -
1] 代表的意义,并且考虑如果 dp[i - 1] 的结值是 0 的话,影不影响结果),然后加
⼀即可,此时 dp[i] = dp[i - 1] + 1
iii. 如果 nums[i] < 0 ,这时候你该蛋疼了,因为在现有的条件下,你根本没办法得到此时
的最⻓⻓度。因为乘法是存在「负负得正」的,单单靠⼀个 dp[i - 1] ,我们⽆法推导
dp[i] 的值。
但是,如果我们知道「以 i - 1 为结尾的所有⼦数组,乘积为负数的最⻓⼦数组的⻓
度」 neg[i - 1] ,那么此时的 dp[i] 是不是就等于 neg[i - 1] + 1 呢?
通过上⾯的分析,我们可以得出,需要两个 dp 表,才能推导出最终的结果。不仅需要⼀个「乘积
为正数的最⻓⼦数组」,还需要⼀个「乘积为负数的最⻓⼦数组」。
1. 状态表⽰:
f[i] 表⽰:以 i 结尾的所有⼦数组中,乘积为「正数」的最⻓⼦数组的⻓度;
g[i] 表⽰:以 i 结尾的所有⼦数组中,乘积为「负数」的最⻓⼦数组的⻓度。
2. 状态转移⽅程:
遍历每⼀个位置的时候,我们要同步更新两个 dp 数组的值。
对于 f[i] ,也就是以 i 为结尾的乘积为「正数」的最⻓⼦数组,根据 nums[i] 的值,可以
分为三种情况:
i. nums[i] = 0 时,所有以 i 为结尾的⼦数组的乘积都不可能是正数,此时 f[i] =
0
ii. nums[i] > 0 时,那么直接找到 f[i - 1] 的值(这⾥请再读⼀遍 f[i - 1] 代表
的意义,并且考虑如果 f[i - 1] 的结值是 0 的话,影不影响结果),然后加⼀即可,
此时 f[i] = f[i - 1] + 1
iii. nums[i] < 0 时,此时我们要看 g[i - 1] 的值(这⾥请再读⼀遍 g[i - 1]
表的意义。因为负负得正,如果我们知道以 i - 1 为结尾的乘积为负数的最⻓⼦数组的
⻓度,加上 1 即可),根据 g[i - 1] 的值,⼜要分两种情况:
1. g[i - 1] = 0 ,说明以 i - 1 为结尾的乘积为负数的最⻓⼦数组是不存在的,⼜
因为 nums[i] < 0 ,所以以 i 结尾的乘积为正数的最⻓⼦数组也是不存在的,此
f[i] = 0
2. g[i - 1] != 0 ,说明以 i - 1 为结尾的乘积为负数的最⻓⼦数组是存在的,⼜
因为 nums[i] < 0 ,所以以 i 结尾的乘积为正数的最⻓⼦数组就等于 g[i -
1] + 1
综上所述, nums[i] < 0 时, f[i] = g[i - 1] == 0 ? 0 : g[i - 1] +
1;
对于 g[i] ,也就是以 i 为结尾的乘积为「负数」的最⻓⼦数组,根据 nums[i] 的值,可以
分为三种情况:
i. nums[i] = 0 时,所有以 i 为结尾的⼦数组的乘积都不可能是负数,此时 g[i] =
0
ii. nums[i] < 0 时,那么直接找到 f[i - 1] 的值(这⾥请再读⼀遍 f[i - 1] 代表
的意义,并且考虑如果 f[i - 1] 的结值是 0 的话,影不影响结果),然后加⼀即可
(因为正数 * 负数 = 负数),此时 g[i] = f[i - 1] + 1
iii. nums[i] > 0 时,此时我们要看 g[i - 1] 的值(这⾥请再读⼀遍 g[i - 1]
表的意义。因为正数 * 负数 = 负数),根据 g[i - 1] 的值,⼜要分两种情况:
1. g[i - 1] = 0 ,说明以 i - 1 为结尾的乘积为负数的最⻓⼦数组是不存在的,⼜
因为 nums[i] > 0 ,所以以 i 结尾的乘积为负数的最⻓⼦数组也是不存在的,此
f[i] = 0
2. g[i - 1] != 0 ,说明以 i - 1 为结尾的乘积为负数的最⻓⼦数组是存在的,⼜
因为 nums[i] > 0 ,所以以 i 结尾的乘积为正数的最⻓⼦数组就等于 g[i -
1] + 1
综上所述, nums[i] > 0 时, g[i] = g[i - 1] == 0 ? 0 : g[i - 1] +
1 ;
这⾥的推导⽐较绕,因为不断的出现「正数和负数」的分情况讨论,我们只需根据下⾯的规则,严
格找到此状态下需要的 dp 数组即可:
i. 正数 * 正数 = 正数
ii. 负数 * 负数 = 正数
iii. 负数 * 正数 = 正数 * 负数 = 负数
3. 初始化:
可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
i. 辅助结点⾥⾯的值要「保证后续填表是正确的」;
ii. 「下标的映射关系」。
在本题中,最前⾯加上⼀个格⼦,并且让 f[0] = g[0] = 0 即可。
4. 填表顺序:
根据「状态转移⽅程」易得,填表顺序为「从左往右,两个表⼀起填」。
5. 返回值:
根据「状态表⽰」,我们要返回 f 表中的最⼤值。

解题代码:

class Solution {
public:
    int getMaxLen(vector<int>& nums) {
        int n=nums.size();
        vector<int>f(n+1,0);
        vector<int>g(n+1,0);
        int ret=INT_MIN;
        for(int i=1;i<=n;i++)
        {
            if(nums[i-1]>0)
            {
                f[i]=f[i-1]+1;
                g[i]=g[i-1]==0?0:g[i-1]+1;
            }
            else if(nums[i-1]<0)
            {
                g[i]=f[i-1]+1;
                f[i]=g[i-1]==0?0:g[i-1]+1;
            }
            ret=max(ret,f[i]);
        }
        return ret;
    }
};

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

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

相关文章

【LLM】基于LLM的agent应用(上)

note 在未来&#xff0c;Agent 还会具备更多的可扩展的空间。 就 Observation 而言&#xff0c;Agent 可以从通过文本输入来观察来理解世界到听觉和视觉的集成&#xff1b;就 Action 而言&#xff0c;Agent 在具身智能的应用场景下&#xff0c;对各种器械进行驱动和操作。 Age…

BGP联盟和团体属性实验

目录 一、实验拓扑 二、实验要求 三、实验步骤 1、IP地址配置 2、ospf配置 3、BGP建邻 4、宣告网段 5、配置团体属性 一、实验拓扑 二、实验要求 1、按照图示配 IP 地址&#xff0c;R2&#xff0c;R3&#xff0c;R4&#xff0c;R5分别配 Loopbacke 口地址作为OSPF的Ro…

Synchronized 关键字的底层原理

目录 synchronized 同步语句块的情况 synchronized 修饰方法的的情况 synchronized 关键字底层原理属于JVM 层面 synchronized 同步语句块的情况 public class SynchronizedDemo {public void method() {synchronized (this) {System.out.println("synchronized 代码块…

hive sql 行列转换 开窗函数 炸裂函数

hive sql 行列转换 开窗函数 炸裂函数 准备原始数据集 学生表 student.csv 讲师表 teacher.csv 课程表 course.csv 分数表 score.csv 员工表 emp.csv 雇员表 employee.csv 电影表 movie.txt 学生表 student.csv 001,彭于晏,1995-05-16,男 002,胡歌,1994-03-20,男 003,周杰伦,…

037、目标检测-算法速览

之——常用算法速览 目录 之——常用算法速览 杂谈 正文 1.区域卷积神经网络 - R-CNN 2.单发多框检测SSD&#xff0c;single shot detection 3.yolo 杂谈 快速过一下目标检测的各类算法。 正文 1.区域卷积神经网络 - R-CNN region_based CNN&#xff0c;奠基性的工作。…

【AI】行业消息精选和分析(23-11-19)

行业动态 1、对标GPTs&#xff0c;微软连夜发布100多项更新&#xff01;微软CEO&#xff1a;Copilot时代来了 2、英伟达联手微软推出AI代工服务 3、全新雅虎搜索将于 2024 年上线&#xff0c;未来还会推出更多 AI 和高级功能 4、Instagram 推出定制 AI 贴纸和滤镜功能&#xff…

【教3妹学编程-算法题】三个无重叠子数组的最大和

2哥 : 3妹&#xff0c;咋啦&#xff1f;一副苦大仇深的样子&#xff1f; 3妹&#xff1a;不开心呀不开心&#xff0c;羽生结弦宣布离婚。 2哥 : 羽生什么&#xff1f; 3妹&#xff1a;羽生结弦&#xff01; 2哥 : 什么结弦&#xff1f; 3妹&#xff1a;羽生结弦&#xff01;&am…

战神传奇【我本沉默精修版】win服务端+双端+充值后台+架设教程

搭建资源下载:战神传奇【我本沉默精修版】win服务端双端充值后台架设教程-海盗空间

安卓手机投屏到电视,跨品牌、跨地域同样可以实现!

在手机网页上看到的视频&#xff0c;也可以投屏到电视上看&#xff01; 长时间使用手机&#xff0c;难免脖子会酸。这时候&#xff0c;如果你将手机屏幕投屏到大电视屏幕&#xff0c;可以减缓脖子的压力&#xff0c;而且大屏的视觉体验更爽。 假设你有一台安卓手机&#xff0c;…

TG Pro v2.87(mac温度风扇速度控制工具)

TG Pro 是适用于 macOS 的温度和风扇速度控制工具&#xff0c;可让您监控 Mac 组件&#xff08;例如 CPU 和 GPU&#xff09;的温度和风扇速度。如果您担心 Mac 过热或想要手动调整风扇速度以降低噪音水平&#xff0c;这将特别有用。 除了温度和风扇监控&#xff0c;TG Pro 还…

解锁数据安全之门:探秘迅软DSE的文件权限控制功能

企业管理者在进行数据安全管控时通常只关注到文件的加密方式&#xff0c;却忽略了以下问题&#xff1a;对于企业内部文档&#xff0c;根据其所承载的涉密程度不同&#xff0c;重要程度也不相同&#xff0c;需要由不同涉密等级的的人员进行处理&#xff0c;这就需要对涉密文档和…

JVM 调优指南

文章目录 为什么要学 JVM一、JVM 整体布局二、Class 文件规范三、类加载模块四、执行引擎五、GC 垃圾回收1 、JVM内存布局2 、 JVM 有哪些主要的垃圾回收器&#xff1f;3 、分代垃圾回收工作机制 六、对 JVM 进行调优的基础思路七、 GC 情况分析实例 JVM调优指南 -- 楼兰 ​ JV…

参考文献格式

目录 期刊会议预印本&#xff08;如arxiv&#xff09; 期刊 找不到页码可以在文献中查看bibtex格式&#xff0c;其中有 外文期刊可在web of science中查找卷号、期号和所在页数&#xff1a; [1] ZHANG F, HU Z Q, FU Y K, et al. A New Identification Method for Surface …

详解Java设计模式之职责链模式

原文&#xff1a;详解Java设计模式之职责链模式_java_脚本之家 责任链模式是一种行为设计模式&#xff0c;使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系&#xff0c;文中通过代码示例给大家介绍的非常详细,需要的朋友可以参考下 − 目…

传奇手游白日门【龙城霸业】win服务端+双端+GM后台+详细教程

搭建资源下载地址&#xff1a;传奇手游白日门【龙城霸业】win服务端双端GM后台详细教程-海盗空间

6.9平衡二叉树(LC110-E)

绝对值函数&#xff1a;abs() 算法&#xff1a; 高度和深度的区别&#xff1a; 节点的高度&#xff1a;节点到叶子节点的距离&#xff08;从下往上&#xff09; 节点的深度&#xff1a;节点到根节点的距离&#xff08;从上往下&#xff09; 逻辑&#xff1a;一个平衡二叉树…

Bert学习笔记(简单入门版)

目 录 一、基础架构 二、输入部分 三、预训练&#xff1a;MLMNSP 3.1 MLM&#xff1a;掩码语言模型 3.1.1 mask模型缺点 3.1.2 mask的概率问题 3.1.3 mask代码实践 3.2 NSP 四、如何微调Bert 五、如何提升BERT下游任务表现 5.1 一般做法 5.2 如何在相同领域数据中进…

C_11微机原理

一、单项选择题&#xff08;本大题共 15 小题&#xff0c;每小题 3分&#xff0c;共45分。在每小题给出的四个备选项中&#xff0c;选出一个正确的答案。&#xff09; .EXE 文件产生在&#xff08;&#xff09;之后。 A.汇编 B. 编辑 C.用软件转换 D.连接 2,十进制-61的8位二进…

Dynamsoft Barcode Reader新框架将医疗视觉提升到新水平

Dynamsoft Vision 框架将医疗保健领域的计算机视觉提升到新的水平 引入图像捕获、内容理解、结果解析和交互式工作流程的聚合 SDK&#xff0c;以简化复杂的流程。 温哥华 – 2023 年 7 月 17 日 – Dynamsoft™ 发布了 Dynamsoft Barcode Reader SDK C Edition v10.0.0。更新…

Redis篇---第七篇

系列文章目录 文章目录 系列文章目录前言一、是否使用过 Redis Cluster 集群,集群的原理是什么?二、 Redis Cluster 集群方案什么情况下会导致整个集群不可用?三、Redis 集群架构模式有哪几种?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分…