leetcode-乘积最大子数组

categories: [计算机通识,数据结构与算法,leetcode系列]
thumbnail: /images/fe/leetcode.jpg
toc: true

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

给你一个整数数组 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]

56-34-3
Fmax530-341080
Fmin56-90-360-12

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

代码如下:

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)
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值