一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
前言
力扣第152题 乘积最大子数组
如下所示:
给你一个整数数组 nums
,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
子数组 是数组的连续子序列。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
一、思路
题目很简短,也很好理解,就是找到数组中 乘积最大的非空连续子数组
。既然说到 乘积最大
,我们直到 正正得正,负负得正
。假设需要求以 nums[i]
结尾的乘积最大子数组,只会有以下几种情况之一:
nums[i]
为正数:则找到以nums[i-1]
结尾的子数组最大的乘积乘上nums[i]
和nums[i]
中,取最大的值保留nums[i]
为负数:则找到以nums[i-1]
结尾的最小乘积(负数)
对上述中
nums[i]
为正数做个特殊解释,此处以nums = [0, 2]
作为例子。很明显以nums[1]
为结尾的最大乘积为2
,即nums[1]
本身。如果乘上以nums[0]
为结尾的最大乘积0
反而会更小。
上面的这个过程,说明求最大乘积的过程是可以分解的,故在这里可以使用 动态规划
。我们的目的只有一个 求以 nums[i] 为结尾的最大乘积和最小乘积(负数)
,因为 负数 x 最小的负数
会得到 最大的正数
。
positiveMax[i]
:以 nums[i]
为结尾的最大乘积
negativeMin[i]
:以 nums[i]
为结尾的最小乘积(负数)
可以推到出如下的动态规划:
nums[i] > 0
:positiveMax[i] = Math.max(positiveMax[i-1] x nums[i], nums[i])
negativeMin[i] = negativeMin[i-1] x nums[i]
nums[i] <= 0
:positiveMax[i] = negativeMin[i-1] x nums[i]
negativeMin[i] = Math.min(positiveMax[i-1] x nums[i], nums[i])
上面分了正负两种情况讨论,需要注意:正数时可能会取 nums[i]
本身,负数时也是同理。
二、实现
实现代码
实现代码与思路中保持一致
public int maxProduct(int[] nums) {
int ret = nums[0];
int len = nums.length;
int[] positiveMax = new int[len]; // 正数最大值
int[] negativeMin = new int[len];
if (nums[0] > 0)
positiveMax[0] = nums[0];
else
negativeMin[0] = nums[0];
for (int i = 1; i < len; ++i) {
if (nums[i] > 0){
positiveMax[i] = Math.max(positiveMax[i-1] * nums[i], nums[i]);
negativeMin[i] = negativeMin[i-1] * nums[i];
} else { // 负数
positiveMax[i] = negativeMin[i-1] * nums[i];
negativeMin[i] = Math.min(positiveMax[i-1] * nums[i], nums[i]);
}
ret = Math.max(positiveMax[i], ret);
}
return ret;
}
测试代码
public static void main(String[] args) {
int[] nums = {2,3,-2,4};
int[] nums1 = {0, 2};
new Number152().maxProduct(nums1);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~