【动态规划】 LeetCode #152 乘积最大子数组

WPF实战:利用Live Charts实现高性能动态曲线可视化 本文详细介绍了如何在WPF中使用Live Charts实现高性能动态曲线可视化,特别适用于工业监控和金融分析等实时数据场景。通过增量渲染、内存复用和硬件加速等核心技术,Live Charts能够高效处理高频数据更新,显著提升图表流畅度。文章提供了从基础实现到工业级优化的完整解决方案,帮助开发者应对各种性能挑战。 阅读详情

题目链接:

LeetCode #152 乘积最大子数组

题目描述:

#152. 乘积最大子数组

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

示例 1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

通过次数70,288 | 提交次数177,501

分析:

原来做过一个题,是求和最大子数组,所以一开始想的是这个题也设 dp[i] 为以 nums[i] 结尾的连续子数组相乘的最大值,但是在测试时会发现问题:

当两个负数中间夹着正数的时候,计算负数的最大值可能要用到前面的最小值,因为负负得正,如:[-3, 2, -5] 最大值应该是(-3)× 2 ×(-5)= 30。

所以我们要记录的不只是最大值,还要记录最小值。

动态规划,设 dp[i][j] 为以 nums[i] 结尾的连续子数组相乘的最大值和最小值, 即二维数组 dp[][] 只有两行,第一行记录最小值,第二行记录最大值。虽然我们记录了最大值和最小值,但是实际最终要求的是最大值,之所以记录最小值,只是针对两个负数之间有正数的情况,这种情况下最小值可能会摇身一变变为最大值。

状态转移方程式:(以 nums[i] 的正负分类讨论)

若 nums[i] = 0, 则 dp[i][0] = 0, dp[i][1] = 0

若 nums[i] > 0:(当前结尾元素为正数)

先分析最大值:(正数 × 正数才会大,去看上一个的最大值)
当 dp[i - 1][1] > 0 时,dp[i][1] = dp[i - 1][1] * nums[i]
否则,dp[i][1] = nums[i]

再来看最小值:(正数 × 负数才会小,去看上一个的最小值)
当 dp[i - 1][0] <= 0 时,dp[i][0] = dp[i - 1][0] * nums[i]

若 nums[i] < 0:(当前结尾元素为负数)

先分析最大值:(一个负数怎么才能尽可能大?乘上一个负数)
当 dp[i - 1][0] < 0, dp[i][1] = dp[i - 1][0] * nums[i]
否则,dp[i][1] = nums[i]

再来看最小值:
当 dp[i - 1][1] > 0, dp[i][0] = dp[i - 1][1] * nums[i]
否则,dp[i][0] = nums[i]

到此就全部分析完了,接下来把上述情况整理汇总一下:

最大值 dp[i][1] = max(dp[i - 1][0] * nums[i] , dp[i - 1][1] * nums[i], nums[i])

最小值 dp[i][0] = min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i], nums[i])

第一次提交:

提交结果:
在这里插入图片描述
代码:

/*
*动态规划,设 dp[i][j] 为以 nums[i] 结尾的连续子数组相乘的最大值和最小值
*即二维数组 dp[][] 只有两行,第一行记录最小值,第二行记录最大值
*虽然我们记录了最大值和最小值,但是实际最终要求的是最大值
*之所以记录最小值,只是针对两个负数之间有正数的情况
*这种情况下最小值可能会摇身一变变为最大值,如:[-3, 2, -5]
*若 nums[i] = 0, 则 dp[i][0] = 0, dp[i][1] = 0
*若 nums[i] > 0, 
*先分析最大值:当 dp[i - 1][1] > 0 时,dp[i][1] = dp[i - 1][1] * nums[i]
*                        否则,dp[i][1] = nums[i]
*再来看最小值:当 dp[i - 1][0] <= 0 时,dp[i][0] = dp[i - 1][0] * nums[i]
*                        否则,dp[i][0] = nums[i] 
*若 nums[i] < 0, 
*先分析最大值:一个负数怎么才能尽可能大?乘上一个负数
*                       当 dp[i - 1][0] < 0, dp[i][1] = dp[i - 1][0] * nums[i]
*                       否则,dp[i][1] = nums[i]
*再来看最小值:当 dp[i - 1][1] > 0, dp[i][0] = dp[i - 1][1] * nums[i]
*                         否则,dp[i][0] = nums[i]
*整理汇总一下:最大值 dp[i][1] = max(dp[i - 1][0] * nums[i] , dp[i - 1][1] * nums[i], nums[i])
*                       最小值 dp[i][0] = min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i], nums[i])  
*/
class Solution {
    public int maxProduct(int[] nums) {
        if(nums.length == 1) return nums[0];
        int result = nums[0];
        int[][] dp = new int[nums.length][2];
        dp[0][0] = dp[0][1] = nums[0];
        for(int i = 1;  i < nums.length; i++){
            dp[i][1] = Math.max(Math.max(dp[i - 1][0] * nums[i] , dp[i - 1][1] * nums[i]), nums[i]);
            dp[i][0] = Math.min(Math.min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i]), nums[i]);
            if(result < dp[i][1]){ result = dp[i][1];}
        }
        return result;
    }
}

优化:

时间复杂度已经是 O(n) 了,用动态规划思想没有可以优化的地方,空间复杂度是 O(n^2),创建了二维数组 dp[][],下面就针对空间复杂度进行优化:

每次计算 dp[i][0] 和 dp[i][1] 时,只会用到前一位的最大值和最小值,不必创建二维数组,用 4 个变量即可

第二次提交:(空间复杂度O(1))

先来看提交结果:
在这里插入图片描述
以下为优化后的代码:

/*
*动态规划,设 dp[i][j] 为以 nums[i] 结尾的连续子数组相乘的最大值和最小值
*即二维数组 dp[][] 只有两行,第一行记录最小值,第二行记录最大值
*虽然我们记录了最大值和最小值,但是实际最终要求的是最大值
*之所以记录最小值,只是针对两个负数之间有正数的情况
*这种情况下最小值可能会摇身一变变为最大值,如:[-3, 2, -5]
*若 nums[i] = 0, 则 dp[i][0] = 0, dp[i][1] = 0
*若 nums[i] > 0, 
*先分析最大值:当 dp[i - 1][1] > 0 时,dp[i][1] = dp[i - 1][1] * nums[i]
*                        否则,dp[i][1] = nums[i]
*再来看最小值:当 dp[i - 1][0] <= 0 时,dp[i][0] = dp[i - 1][0] * nums[i]
*                        否则,dp[i][0] = nums[i] 
*若 nums[i] < 0, 
*先分析最大值:一个负数怎么才能尽可能大?乘上一个负数
*                       当 dp[i - 1][0] < 0, dp[i][1] = dp[i - 1][0] * nums[i]
*                       否则,dp[i][1] = nums[i]
*再来看最小值:当 dp[i - 1][1] > 0, dp[i][0] = dp[i - 1][1] * nums[i]
*                         否则,dp[i][0] = nums[i]
*整理汇总一下:最大值 dp[i][1] = max(dp[i - 1][0] * nums[i] , dp[i - 1][1] * nums[i], nums[i])
*                       最小值 dp[i][0] = min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i], nums[i])  
*优化:每次计算 dp[i][0] 和 dp[i][1] 时,只会用到前一位的最大值和最小值,不必创建二维数组,用 4 个变量即可
*/
class Solution {
    public int maxProduct(int[] nums) {
        if(nums.length == 1) return nums[0];
        int result = nums[0];
        int preMin = nums[0], preMax = nums[0];//preMin和preMax分别记录上一个的最小值、最大值
        int min = nums[0], max = nums[0];
        for(int i = 1;  i < nums.length; i++){
            max = Math.max(Math.max(preMin * nums[i] , preMax * nums[i]), nums[i]);
            min = Math.min(Math.min(preMin * nums[i], preMax * nums[i]), nums[i]);
            if(result < max){ result = max;}
            preMin = min;
            preMax = max;
        }
        return result;
    }
}

小结:

1 . 不要想到用二维数组 dp[][]就觉得这个方法应该被舍弃,二维数组优化以后也可能变为创建一位数组 dp[],或者只需要几个变量。

2 . 提交结果里执行用时很长,并不代表这个算法的时间复杂度高,两次提交我们并没有改变时间复杂度,只是对空间复杂度进行了优化,而提交结果中发生显著变化的其实是“执行用时”,从“在所有 Java 提交中击败了 19.43% 的用户”变为了“在所有 Java 提交中击败了 90.51% 的用户”。因为执行用时不仅仅与时间复杂度有关,还包括了创建数组的时间、从数组读数据和从变量读数据等等很多细节上的用时;同理,内存消耗也不仅仅与空间复杂度有关,实际上这些内存消耗往往是被测试用例占了大头。

3 . 这个题还有其他的解法,比如“先计算从左到右的相乘的最大值,再计算从右到左的最大值,再将两组最大值相比”,本文只介绍了动态规划的解法,更多解法可以去最上方题目链接中的“评论”和“题解”里找。

VS Code 重大更新:Agent Skills完美支持! 代码不会骗人,但你的 LLM 可能会编个故事——除非你给它一本《技能手册》。——某位深夜调试成功的 Go 工程师。 阅读详情

相关推荐

VMware ESXi 7.0下Intel网卡SR-IOV配置实战:解决虚拟化网络延迟问题

本文详细介绍了在VMware ESXi 7.0环境下为Intel网卡配置SR-IOV(单根I/O虚拟化)的完整实战流程。通过硬件辅助直通技术,虚拟机可直接访问物理网卡资源,有效绕过虚拟化层瓶颈,从而显著降低网络延迟和CPU开销,适用于金融交易、实时计算等对性能敏感的场景。

embedding5hiker的博客 552

leecode #152 乘积最大子数组 | 刷题之路第二站——动态规划类问题

题号 152 题目描述 给你一个整数数组nums,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 示例1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 示例2: 输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 解题思路一——暴力法 对于给定数组 nums 中的每个元素 nums[ i ],分别计算: nums[ 0 ] ~ nums...

m0_37714470的博客 192

图解链表 —— JAVA中的单链表基本操作

文章目录1. 什么是链表2. 链表的种类3. 创建单链表3.1 创建 Node 类(车厢类)3.2 创建 MySingleList (火车类)4. 单链表的基本操作4.1 增加链表元素4.1.1 在链表头部添加元素4.1.2 在链表任意位置添加元素4.1.3 在链表尾部添加元素4.2 删除链表元素4.2.1 删除第一个节点元素4.2.2 删除任意位置 index 元素4.2.3 删除链表中指定元素的第一个节点4.2.4 删除链表的所有指定元素4.3 查找链表元素4.3.1 判断链表中是否包含元素 data4

AlinaQ05的博客 2501

LeetCode 之 乘积最大子数组

乘积最大子数组1. 暴力遍历2. 动态规划2.1 定义子问题2.2 状态转移方程2.3 返回最值2.4 报错解决3. 空间优化参考链接 题目要求找出数组 nums 中乘积最大的连续子数组,最直接的办法是遍历整个数组,穷举以数组元素 nums[i] 为开头的所有连续子数组,通过比较所有连续子数组的乘积,找到最大值,并返回。 可是穷举所有子数组的乘积的过程中,存在很多重复计算。因此可以考虑使用动态规划的思想来优化算法。 知识点: 动态规划及其空间优化 1. 暴力遍历 这种方法通过穷举所有可能的结果,得到最大值

qq_39220334的博客 1781

360加固DEX解密与ELF修复技术解析

本文深入解析360加固的DEX解密与ELF修复技术,详细介绍了其多层保护机制、Java层入口分析、Native层加载流程及反调试绕过技巧。通过RC4和zlib解密技术,结合Frida工具实现内存Dump和ELF文件修复,为逆向工程师提供实用解决方案。

weixin_29327525的博客 506

【阿里云大模型高级工程师ACP习题集】2.1 用大模型构建新人答疑机器人

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 2606

【leetcode热题】乘积最大子数组

给你一个整数数组nums,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。测试用例的答案是一个整数。6子数组 [2,3] 有最大乘积 6。0结果不能为 2, 因为 [-2,-1] 不是子数组。

kiugvui的博客 1672

深入排查127.0.0.1拒绝连接:从端口占用到Tomcat服务启动的完整解决方案

本文针对开发者访问127.0.0.1时遭遇“拒绝连接”的常见问题,提供了一套完整的排查与解决方案。文章从端口占用检查入手,详细讲解了使用netstat命令识别进程,并深入分析了服务监听地址、IPv6配置、防火墙以及Tomcat服务安装与启动等核心环节。通过实战演练,指导读者系统性地解决从网络层到应用层的各类连接问题,最终确保本地服务成功运行并可通过本地回环地址正常访问。

weixin_29279047的博客 3183

力扣(LeetCode)152. 乘积最大子数组(C++)

【墨染】序列dp之乘积最大子数组,朴素dp || 滚动数组优化

墨染 1250

宇瞳杯安防镜头设计

宇瞳杯安防镜头设计

weixin_72050316的博客 1507

akamai3简单分析

akamai流程的简单分析

记录一些web逆向的过程 916

子数组最大乘积

题目:给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。 例如:[-2.5,4,0,3,0.5,8,-1]其中子数组[3,0.5,8]的乘积最大,为12; 算法思想:创建新的double型变量:max,min,MAX。当数组记录到i位置时,此时max记录(arr[i],max*arr[i],min*arr[i])其中的最大值。 min记录(arr[i],max*arr[i],min*arr[i])中的最小值,记录最小值的目的是:当min为负数时且arr[i]为负数

qq_43774324的博客 750

机器人中的数值优化(一)—— 数学优化、凸集合与凸函数

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考,主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等,本系列文章篇数较多,不定期更新,上半部分介绍无约束优化,下半部分介绍带约束的优化,中间会穿插一些路径规划方面的应用实例。

慕羽★的博客 2521

高级编程技术 Python 第八周作业

Maximum Subarray (#53)来源:https://leetcode.com/problems/maximum-subarray/description/题意:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。示例:输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最...

Mike_Panda的博客 539

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

LeetCode 152. 乘积最大子数组 | Python

使用动态规划,根据题意进行状态设计,推导出状态转移方程,用代码加以实现,进而解决《152. 乘积最大子数组》问题

"大梦三千秋的博客 1715

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【LeetCode】152、乘积最大子数组

所以, 每一步, 都取上述三种情况的最小值和最大值. 逐步向后递推.通过设置 mi, ma 为 1, 1, 即可从0开始遍历了。为了简化代码, 可以不从1开始遍历。

呆呆的猫的博客 1393

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

LeetCode-152. 乘积最大子数组【数组 动态规划】

即使用二维状态数组同时记录乘积的最大值和最小值,本来写了一堆文字的,后来看太长了,好多废话,直接看代码比较清楚一些。dp[i][1] 表示:以 nums[i] 结尾的连续子序列的乘积的最大值;dp[i][0] 表示:以 nums[i] 结尾的连续子序列的乘积的最小值。当 nums[i] = 0 的时候包含在上面二者之中,无需单独讨论。解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。输入: nums = [2,3,-2,4]输入: nums = [-2,0,-1]时间复杂度:O(n)

zik的博客 1363

数组之乘积最大子数组

LeetCode 152. 乘积最大子数组 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 解析: 不包含0的情况 1.0 全为正数 这种情况最简单,直接所有结果相乘即可。 2.1 偶数个负数 负负得正,这种情况也直

AndyJ的学习之旅 1277

152. 乘积最大子数组_最大最小策略

152. 乘积最大子数组 1.题目描述 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字)。 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 来源:力扣(LeetCode) 链接:http...

achong_2050的博客 794

Leetcode-152.乘积最大连续子数组

题目来源:https://leetcode-cn.com/problems/maximum-product-subarray/ 给你一个整数数组 nums,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字)。 示例 1: 输入: [2,3,-2,4] 输出: 6 解释:子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释:...

sinat_41473555的博客 786

LeetCode 152. 乘积最大子数组(Python、动态规划)

“最大子数组和”的变型 题目描述 动态规划 思路和算法 如果我们用 fmax⁡(i)f_{\max}(i)fmax​(i) 来表示以第 iii 个元素结尾的乘积最大子数组的乘积,aaa 表示输入参数 numsnumsnums,那么根据「53. 最大子序和」的经验,我们很容易推导出这样的状态转移方程: fmax⁡(i)=max⁡i=1n{f(i−1)×ai,ai} f_{\max}(i) = \max_{i = 1}^{n} \{ f(i - 1) \times a_i, a_i \} fmax​(i).

稚嫩的劢劢的博客 1048

152 乘积最大子数组(动态规划)

1. 问题描述: 给你一个整数数组 nums,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 示例 1: 输入: [2,3,-2,4] 输出: 6 解释:子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释:结果不能为 2, 因为 [-2,-1] 不是子数组。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/maximum-product-suba...

二哈 297

力扣热门算法题 152. 乘积最大子数组,153. 寻找旋转排序数组中的最小值,160. 相交链表

152. 乘积最大子数组,153. 寻找旋转排序数组中的最小值,160. 相交链表​,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.28可通过leetcode所有测试用例。

引用原创内容标明出处即可 1302

动态规划刷题笔记(一):乘积最大子数组,最长有效括号

ps:笔记和代码按本人理解整理,重思路

学习记录 772

动态规划:力扣152. 乘积最大子数组

1、题目描述: 2、题解: 动态规划: 动态规划问题,弄清楚三点: 1、重复子问题; 2、最优子结构; 3、无后效性。 动态规划: 1、状态定义; 2、状态转移方程; 3、初始化;base case 4、输出; 5、思考状态压缩。 可以用递归去求,但是会存在重叠子问题,加个备忘录可以解决重复问题。 3、复杂度分析: ...

weixin_42042056的博客 209

152. 乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/maximum-product-subarray 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ———————————— 解题思路:使用动态规划,维护两个

然后就去远行 259
上一篇: 【动态规划】 LeetCode #面试题 08.01. 三步问题
下一篇: 【动态规划】 LeetCode #221 最大正方形
Code_Yilia
博客等级 码龄11年 4粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值