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 ...
随机推荐
- halcon如何识别硬币?
halcon如何识别硬币? 前言 最近一直在学习halcon,在此做了一个案例,分享给大家,效果图如下: 1.思路分析 通过观察,发现1元,5角,1角,它们在面值的文字描述不一样,硬币显示的花纹不一样 ...
- lambda、map、reduce、filter、sorted函数
# lambda 函数from functools import reducea = lambda x: x ** 2print(a(3))def power(func, l=[]): return ...
- Ubuntu环境下LLVM 15.0 完全编译 附windows编译LLVM master
1. 预先安装 sudo apt install ninja-build sudo apt install llvm clang # 第一次编译需要 sudo apt-get install libn ...
- POST请求发送的表单数据和json数据的区别及python代码实现
前言 这篇博客会介绍最常见post 请求form表单数据和json数据 数据类型之间的区别, urllib代码的实现(python), requests库实现, 以及如何使用postman软件发送这些 ...
- Day31面向对象之魔法方法
Day31面向对象之魔法方法 类的常用魔法方法如下 序号 双下方法 触发条件 1 init 对象添加独有数据的时候自动触发 2 str 对象被执行打印操作的时候自动触发 3 call 对象加括号调用的 ...
- Qt_CLion
目录 安装Qt和CLion 配置 CLion配置Qt的资源文件系统 在项目根文件夹下创建一个资源文件夹 在项目根目录下创建一个qrc文件 安装Qt和CLion 相关的安装网上有很多教程,安装步骤这里不 ...
- week_3
Andrew Ng机器学习笔记 Week_3 -- -Logistic Regression This week, we'll be covering logistic regression. Log ...
- vue elementui弹框内 富文本编辑器的使用,及踩坑
最近vue项目中遇到弹框内使用富文本编辑器,遇到最大的问题是,在打开弹框后才能创建富文本编辑器,并且只能创建一次,多次点击弹框,报错: Error in v-on handler: "Err ...
- 网络编程 UDP套接字
第十二章 UDP套接字 12.1 前言 上一章讲述了TCP通信方式,它是基于流的面向连接的网络通信.UDP是IP协议上的另一种传输协议. TCP和UDP都是端到端的通信协议,都处于TCP/IP网络模型 ...
- gRPC入门与实操(.NET篇)
为什么选择 gRPC 历史 长久以来,我们在前后端交互时使用WebApi + JSON方式,后端服务之间调用同样如此(或者更久远之前的WCF + XML方式).WebApi + JSON 是优选的,很 ...