题目: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为结尾的子数组的最小乘积Mnums[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:乘积最大子数组(动态规划)的更多相关文章

  1. [LeetCode] 53. Maximum Subarray 最大子数组 --动态规划+分治

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  2. LeetCode HOT 100:最大子数组和

    题目:53. 最大子数组和 题目描述: 给你一个整数数组,在该数组的所有子数组中,找到一个子数组中所有元素相加和最大,返回这个最大的和.子数组就是一个数组中,由一个或几个下标连续的元素,组成的小数组, ...

  3. leetcode 刷题(数组篇)152题 乘积最大子数组 (动态规划)

    题目描述 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积. 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子 ...

  4. 1. 线性DP 152. 乘积最大子数组

    152. 乘积最大子数组  https://leetcode-cn.com/problems/maximum-product-subarray/ func maxProduct(nums []int) ...

  5. [LeetCode] 53. Maximum Subarray 最大子数组

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  6. [leetcode]53. Maximum Subarray最大子数组和

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  7. Leetcode题目152.乘积最大子序列(动态规划-中等)

    题目描述: 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6 ...

  8. LeetCode HOT 100:在排序数组中查找元素的第一个和最后一个位置

    题目:34. 在排序数组中查找元素的第一个和最后一个位置 题目描述: 给你一个递增数组,和一个目标值target,最终返回数组中第一次出现target和最后一次出现target的下标.如果该数组中没有 ...

  9. LeetCode Top 100 Liked 点赞最高的 100 道算法题

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:刷题顺序,刷题路径,好题,top100,怎么刷题,Leet ...

  10. [LeetCode] Maximum Product Subarray 求最大子数组乘积

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

随机推荐

  1. C语言算法入门

    2018年11月2日  leetcode的确是一个不错的网站,希望能提升自己的算法力 int* twoSum(int* nums, int numsSize, int target) { } 出现的第 ...

  2. JUnit 5 单元测试教程

    点赞再看,动力无限. 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. 在软件开发过程中,我们通常都需要测试 ...

  3. 注册IBMlinuxone并使用xshell登陆

    登陆地址:https://linuxone.cloud.marist.edu/#/login 注册地址:https://linuxone.cloud.marist.edu/#/register?fla ...

  4. Web Api出现500 Internal Server Error 错误

    在测试环境一切正常,但是部署到了生产环境发现一直报错.查询网上的方法设置了权限等等.都没有解决 原来发现是数据库连接字符串的问题.只需要把数据库连接字符串修改正确即可!

  5. JUC-学习笔记

    传统的多线程开发方式 implements Runnable public class oldThreadDev implements Runnable { @Override public void ...

  6. 关于python导包问题(新手向)

    包和模块 首先要弄清这两个概念, 在python 中 一个文件夹中包含__init__.py 文件(这个文件是包的初始化文件,在你导入包或包下面的模块的时候,这个文件会最开始运行),就会被python ...

  7. python-面向过程与函数式

    面向过程与函数式 面向过程 "面向过程"核心是"过程"二字,"过程"指的是解决问题的步骤,即先干什么再干什么......,基于面向过程开发程 ...

  8. 【Java SE进阶】Day03 数据结构、List、Set、Collections

    一.数据结构 1.红黑树 根黑子黑红子黑 接近平衡树(左右孩子数量相同),查询叶子快慢次数不超过2倍 二.List 1.概述 元素有序 线性存储 带有索引 可以重复 2.常用方法 增:add(I,E) ...

  9. 【SQL知识】SQL中的join操作总结:内连接、外连接(左右全)

    一.含义 基于表之间的共同字段,把来自两个或多个表的行结合起来 二.分类 内连接:join / inner join 外连接:left join / right join / full outer j ...

  10. 【Flink】概念、入门、部署(yarn和standalone模式)、架构(组件和运行流程)、批处理、流处理API、window、时间语义、Wartermark、ProcessFunction、状态编程、Table API和SQL、CEP、面试题

    一.Flink简介 1.概述 Apache Flink是为分布式.高性能.随时可用以及准确的流处理应用程序打造的开源流处理框架 对无界和有界数据流进行有状态计算 2.重要特点 (1)事件驱动型:从一个 ...