leetcode-乘积最大子数组

乘积最大子数组(难度:中等)

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

结题思路:
做这道题时如果做过前面leetcode的数列最大字段和,很容易联想到相同的动态规划算法。例如[5, 6, -3, 4, -3],用之前的想法,我们很容易得出状态转移方程:

就是对于当前元素,要么加入到他前面元素的段中,要么自己做一个新段。这个时候很容易得出下面这个dp数组:[5, 30, -3, 4, -3],于是得出答案是30

但是很明显答案是错的,数组所有元素相乘结果5x6x(-3)x4x(-3)才是最大的值。出现这个问题的原因是我们这个办法没考虑数组中负数的情况,而把他们粗暴地一步步相乘对比。

我们可以根据正负性进行分类讨论。

考虑当前位置如果是一个负数的话,那么我们希望以它前一个位置结尾的段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。

综上所述,这道题我们需要维护两个状态数组,一个保存截止到当前元素最大的乘积,另一个保存截止到当前,最小的乘积

状态转移方程如下:

以上面提到的例子为例:
[5, 6, -3, 4, -3]

5 6 -3 4 -3
Fmax 5 30 -3 4 1080
Fmin 5 6 -90 -360 -12

在Fmax中找到最大值1080就是这道题的答案

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
var maxProduct = function(nums) {
let len = nums.length
if(len === 0){
return 0
}
let Fmax =[], Fmin = []
Fmax[0] = Fmin[0] = nums[0]
for(let i = 1; i < len; i++){
Fmax[i] = Math.max(Fmax[i - 1] * nums[i], Fmin[i - 1] * nums[i], nums[i])
Fmin[i] = Math.min(Fmax[i - 1] * nums[i], Fmin[i - 1] * nums[i], nums[i])
}
return Math.max.apply(null, Fmax)
};
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2021 AURORA_ZXH
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信