Skip to content
本页目录

0152-乘积最大子数组

https://leetcode.cn/problems/maximum-product-subarray/

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

示例 1:

输入: [2,3,-2,4]
输出: 6

解释:子数组 [2,3] 有最大乘积 6。 示例 2:

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

解题思路1: 参考最大子序和,考虑符号(imax,imin交换)

这道题可以参考 0053-最大子序和,但是需要注意的是,乘积中有负数的存在,会归为最小,但是如果两个负数相乘,结果为整数,可能又是一个大叔。 如 【-2,3,-4】 结果不是3,而是 -2 * 3 * -4 = 24。 因此,我们处理在记录最大值的同时,还需要记录最小值。 在遍历到 nums[i] 时,

  1. 如果 nums[i] 是正数,则正常处理 maxValue = max(maxValue * nums[i], nums[i])
  2. 如果 nums[i] 是负数,那么乘积最大值将变为最小值,最小值将变为最大值,因此交换当前的 maxValue 和 minValue,再和当前值相乘,就会得到正确的最大值和最小值

参考代码 imax and imin

csharp
public class Solution {
    public int MaxProduct(int[] nums) {
        if(nums.Length == 0){
            return 0;
        }
        int max = nums[0];
        int imax = nums[0]; //保存最大
        int imin = nums[0]; //保存最小
        for(int i=1; i<nums.Length; i++){
            if(nums[i] < 0){ 
                //当nums[i]为负数的时候,那么会导致乘积最大的变成最小的,最小的变成最大的,因此先交换一下,他们继续乘积会得到正确的结果
                //imin 起作用就在此刻
                int tmp = imax;
                imax = imin;
                imin = tmp;
            }
            imax = Math.Max(imax * nums[i], nums[i]);
            imin = Math.Min(imin * nums[i], nums[i]);
            max = Math.Max(max,imax);
        }
        return max;
    }
}

解题思路2:从0分隔考虑负数个数

当数组中没有0的时候,分为两种情况:

  1. 当负数个数为偶数的时候,则整个数组的各个数值线程就是最大值。
  2. 当负数个数为奇数的时候,从左边乘到最后一个负数停止有一个最大值(再往下乘都是负数),从右边开始往左乘也有一个最大值,取其中的最大值(再往下乘也是负数)

当数组中有0的时候,则从0开始重新计算

该方法确实很巧妙

csharp
public class Solution{
	public int MaxProduct(int[] nums){
		int result = 1;
		int max = int.MinValue;
		//从左往右算
		for(int i=0; i<nums.Length; i++){
			result *= nums[i];
			max = Math.Max(result,max);
			if(nums[i] == 0){
				result = 1;
			}
		}
		//从右往左算
		result = 1;
		for(int i=nums.Length -1; i>=0; i--){
			result *= nums[i];
			max = Math.Max(result,max);
			if(nums[i] == 0){
				result = 1;
			}
		}
		return max;
	}
}

Released under the MIT License.