152. 乘积最大子数组

152. 乘积最大子数组

题目描述

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

示例 1:

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

示例 2:

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

题解:

动态规划。

f[i] 表示以 nums[i] 结尾, nums[0...i] 中最大子数组乘积,转移方程:f[i] = max{f[i - 1] * nums[i], nums[i]}

如果这题是 最大连续子数组和 问题,这个方程没问题,但是这题是 乘积 ,乘积意味着可以 负负得正 ,可能得到更大的结果。

假设 nums = {5, 6, -3, 4, -3} ,按上述转移得到的 f = {5, 30, -3, 4, -3} ,最大结果为 30 ,而实际结果为所有元素的乘积,出现这种情况就是因为我们少考虑了 负数 的情况。

所以,我们需要维护一个 fmin[i] ,表示以 nums[i] 结尾,nums[0...i] 中最小子数组乘积,设前面的 f[i] 重新记为 fmax[i] ,那么转移方程为:

  • fmax[i] = max{ fmax[i - 1] * nums[i], fmin[i - 1] * nums[i], nums[i] }
  • fmin[i] = min{ fmax[i - 1] * nums[i], fmin[i - 1] * nums[i], nums[i] }

时间复杂度: O ( n ) O(n) O(n)

额外空间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if ( !n ) return 0;
        int ret = nums[0];
        vector<int> fmin(n), fmax(n);
        fmin[0] = fmax[0] = nums[0];
        for ( int i = 1; i < n; ++i ) {
            fmax[i] = max( {fmax[i - 1] * nums[i], fmin[i - 1] * nums[i], nums[i]} );
            fmin[i] = min( {fmax[i - 1] * nums[i], fmin[i - 1] * nums[i], nums[i]} );
            ret = max( ret, fmax[i] );
        }
        return ret;
    }
};
/*
时间:4ms,击败:92.26%
内存:11.7MB,击败:58.58%
*/

可以发现,f 只跟 f[i - 1] 有关,使用滚动数组优化:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if ( !nums.size() ) return 0;
        int ret = nums[0];
        int fmax = nums[0], fmin = nums[0];
        for ( int i = 1, pre; i < nums.size(); ++i ) {
            pre = fmax;
            fmax = max( {pre * nums[i], fmin * nums[i], nums[i]} );
            fmin = min( {pre * nums[i], fmin * nums[i], nums[i]} );
            ret = max( {ret, fmax} );
        }
        return ret;
    }
};
/*
时间:4ms,击败:92.26%
内存:11.3MB,击败:98.81%
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值