LeetCode HOT 100:乘积最大子数组(动态规划)
题目:152. 乘积最大子数组
题目描述:
给你一个整数数组,在该数组的所有子数组中,找到一个子数组中所有元素相乘积最大,返回这个最大的积。子数组就是一个数组中,由一个或几个下标连续的元素,组成的小数组,就叫原数组的子数组。
思路:
这一题和题目:53. 最大子数组和很像。但是又复杂了一点。所以建议先搞懂53题,再来看这道题。在53题曾经说过求子数组问题,都可以向一种思维上靠拢。即以某一个元素为结尾的子数组中,得到一个结果。然后以每一个元素都作为结尾,得到很多个结果,然后在这些结果中进行比较,一定得到正确的结果。
而本题和加法又不太一样,加法比如说想找到以每一个元素为结尾的子数组的最大和,只需要前一个元素为结尾的子数组最大和能拿到,就可以得到该元素为结尾的子数组的最大和。
举个例子:加法中,数组为nums
,想要得到下标i
为结尾的子数组的最大和X
,只需要得到下标i-1
为结尾的子数组的最大和Y
,然后选择要不要加上nums[i]
就可以得到了。即 X = Math.max(nums[i], Y + nums[i])
。即最大值只会出现在nums[i]
和Y + nums[i]
中选择。
但是乘法不一样,乘法会有负负得正。乘积最大值,不仅会出现在nums[i]
、Y * nums[i]
中。如果nums[i]
是负值,下标i-1
为结尾的子数组的最小乘积M
,nums[i] * M
也可能是乘积最大值。
举个例子:[100, 6, -2, -3]
,以-3
结尾的子数组的最大乘积就是-3 * -1200(以-2为结尾的子数组的最小乘积) = 3600
。
所以,乘积需要得到两个结果,以某一下标结尾的子数组中最大乘积以及最小乘积。
步骤:
1、初始化动态规划数组,以0
下标结尾的子数组最大乘积、最小乘积都是nums[0]
本身
2、在循环中,通过i - 1
的最大乘积和最小乘积,结合公式,得到三条数据,三者进行比较,得到i
的最大乘积和最小乘积,更新dp
数组,以及判断最大乘积是否需要更新
3、循环结束后,返回最大乘积
代码:
未优化空间的动态规划版本
public int maxProduct(int[] nums) {
int n = nums.length;
int[] dpMax = new int[n];
int[] dpMin = new int[n];
// 记录以 0 为结尾的子数组的最大累乘积和最小累乘积
dpMax[0] = nums[0];
dpMin[0] = nums[0];
int ans = nums[0];
for (int i = 1; i < nums.length; i++) {
// 记录三种可能性
int p1 = nums[i];
int p2 = nums[i] * dpMax[i - 1];
int p3 = nums[i] * dpMin[i - 1];
// 从三种可能性中取最大累乘积和最小累乘积
int curMax = Math.max(p1, Math.max(p2, p3));
int curMin = Math.min(p1, Math.min(p2, p3));
// 将最大累乘积与ans比较
ans = Math.max(ans, curMax);
// 更新以 i 为结尾的子数组的最大累乘积和最小累乘积
dpMax[i] = curMax;
dpMin[i] = curMin;
}
return ans;
}
空间优化代码
// 因为dp[i]只和dp[i - 1]有关,所以可以优化空间
public int maxProduct(int[] nums) {
// 记录以 0 为结尾的子数组的最大累乘积
int preMax = nums[0];
// 记录以 0 为结尾的子数组的最小累乘积
int preMin = nums[0];
int ans = nums[0];
for (int i = 1; i < nums.length; i++) {
// 记录三种可能性
int p1 = nums[i];
int p2 = nums[i] * preMax;
int p3 = nums[i] * preMin;
// 从三种可能性中取最大累乘积和最小累乘积
int curMax = Math.max(p1, Math.max(p2, p3));
int curMin = Math.min(p1, Math.min(p2, p3));
// 将最大累乘积与ans比较
ans = Math.max(ans, curMax);
// 更新以 i 为结尾的子数组的最大累乘积和最小累乘积
preMax = curMax;
preMin = curMin;
}
return ans;
}
LeetCode HOT 100:乘积最大子数组(动态规划)的更多相关文章
- [LeetCode] 53. Maximum Subarray 最大子数组 --动态规划+分治
Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...
- LeetCode HOT 100:最大子数组和
题目:53. 最大子数组和 题目描述: 给你一个整数数组,在该数组的所有子数组中,找到一个子数组中所有元素相加和最大,返回这个最大的和.子数组就是一个数组中,由一个或几个下标连续的元素,组成的小数组, ...
- leetcode 刷题(数组篇)152题 乘积最大子数组 (动态规划)
题目描述 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积. 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子 ...
- 1. 线性DP 152. 乘积最大子数组
152. 乘积最大子数组 https://leetcode-cn.com/problems/maximum-product-subarray/ func maxProduct(nums []int) ...
- [LeetCode] 53. Maximum Subarray 最大子数组
Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...
- [leetcode]53. Maximum Subarray最大子数组和
Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...
- Leetcode题目152.乘积最大子序列(动态规划-中等)
题目描述: 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6 ...
- LeetCode HOT 100:在排序数组中查找元素的第一个和最后一个位置
题目:34. 在排序数组中查找元素的第一个和最后一个位置 题目描述: 给你一个递增数组,和一个目标值target,最终返回数组中第一次出现target和最后一次出现target的下标.如果该数组中没有 ...
- LeetCode Top 100 Liked 点赞最高的 100 道算法题
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:刷题顺序,刷题路径,好题,top100,怎么刷题,Leet ...
- [LeetCode] Maximum Product Subarray 求最大子数组乘积
Find the contiguous subarray within an array (containing at least one number) which has the largest ...
随机推荐
- jdk线程池ThreadPoolExecutor优雅停止原理解析(自己动手实现线程池)(二)
jdk线程池工作原理解析(二) 本篇博客是jdk线程池ThreadPoolExecutor工作原理解析系列博客的第二篇,在第一篇博客中从源码层面分析了ThreadPoolExecutor在RUNNIN ...
- polkit(ploicykit)特权提升漏洞解决方案
一.[概述] polkit 的 pkexec 存在本地权限提升漏洞,已获得普通权限的攻击者可通过此漏洞获取root权限,漏洞利用难度低. pkexec是一个Linux下Polkit里的setuid工具 ...
- 5 STL-string
重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦! 生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦! 写在前面,本篇章主要介绍S ...
- 【kafka】JDBC connector进行表数据增量同步过程中的源表与目标表时间不一致问题解决
〇.参考资料 一.现象 1.Oracle源表数据 2.PG同步后的表数据 3.现象 时间不一致,差了8个小时 4.查看对应的connector信息 (1)source { "connecto ...
- 对于async和await的使用方式、作用效果不怎么理解 ?没关系,初步看这篇就够了
结论 同步还是异步,区别如下: 同步:你使用 await 修饰符去调用一个异步(async)方法(是异步方法,不过是阻塞式的,可简单理解为同步): 异步:你获取异步方法返回的 Task,就是异步(后文 ...
- for循环结构、range方法
目录 今日内容总结 whlie补充说明 for循环结构 range方法 练习 今日内容总结 whlie补充说明 1.死循环 真正死循环是一旦执行 CPU功耗会急速上升 直到系统采取紧急措施 尽量不要让 ...
- 对一个序列双重argsort的含义
学习笔记:由numpy.argsort()引发的思考 一.numpy.argsort() 函数定义 函数的定义 首先函数的定义比较简洁: argsort()函数是将x中的元素从小到大排列,提取其对应的 ...
- 【转载】SQL SERVER 存储过程中执行动态Sql语句
MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就 ...
- 一个开放源代码,实现动态IL注入(Hook或补丁工具)框架:Lib.Harmony(Patch,PatchAll,Prefix,Postfix,Transpiler)
详情请参考原文:一个开放源代码,实现动态IL注入(Hook或补丁工具)框架:Lib.Harmony
- [OpenCV实战]44 使用OpenCV进行图像超分放大
图像超分辨率(Image Super Resolution)是指从低分辨率图像或图像序列得到高分辨率图像.图像超分辨率是计算机视觉领域中一个非常重要的研究问题,广泛应用于医学图像分析.生物识别.视频监 ...