链接
问题
给你一个整数数组 nums
,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
题解
题解1: 动态规划
思路:
第i个元素的最优解并不是在第i个元素的最优解基础上实现的; 因为, 当计算到第i个元素时: 如果 i < 0, 那么当前i个元素的乘积 < 0时最大, 如果 i > 0, 那么当前i个元素的乘积 > 0时最大, 所以需要维护两个数组: 一个维护前 i 个元素乘积的最大值, 一个维护前 i 个元素乘积的最小值, 当计算前 i 个元素的最大乘积时, 需要计算nums[i] 与 乘积的最大值和乘积的最小值进行计算, 并且加上nums[i] 本身, 比较出三者的最大值和最小值, 更新至两个数组中
这里为什么要将 nums[i] 加入比较中? 因为, 如果前 i 个元素的最小乘积为 0 时, 前 i+1 个元素的最小乘积为 nums[i]
/**
* 动态规划
*/
public int maxProduct1(int[] nums) {
if(nums == null || nums.length == 0) return 0;
int length = nums.length;
if(length == 1) return nums[0];
int[] maxDP = new int[length];
int[] minDP = new int[length];
maxDP[0] = nums[0];
minDP[0] = nums[0];
for (int i = 1; i < length; i++) {
/**
* 当计算到第i个元素时, 如果 i < 0, 那么当前i个元素的乘积 < 0时最大
* 如果 i > 0, 那么当前i个元素的乘积 > 0时最大
*/
maxDP[i] = Math.max(maxDP[i-1] * nums[i],Math.max(minDP[i-1] * nums[i],nums[i]));
minDP[i] = Math.min(maxDP[i-1] * nums[i],Math.min(minDP[i-1] * nums[i],nums[i]));
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < length; i++) {
max = Math.max(max,maxDP[i]);
}
return max;
}
复杂度分析
时间复杂度: O(n)
空间复杂度: O(n)
题解2: 动态规划 -- 空间复杂度优化
/**
* 动态规划 -- 空间复杂度优化
*/
public int maxProduct(int[] nums) {
if(nums == null || nums.length == 0) return 0;
int length = nums.length;
if(length == 1) return nums[0];
int maxDP = nums[0];
int minDP = nums[0];
int max = nums[0];
for (int i = 1; i < length; i++) {
int tmpMaxDP = maxDP,tmpMinDP = minDP;
maxDP = Math.max(tmpMaxDP * nums[i],Math.max(tmpMinDP * nums[i],nums[i]));
minDP = Math.min(tmpMaxDP * nums[i],Math.min(tmpMinDP * nums[i],nums[i]));
max = Math.max(max,maxDP);
}
return max;
}
复杂度分析
时间复杂度: O(n)
空间复杂度: O(1)