# Leetcode 152. 乘积最大子数组,分享一个简单直观的解法
# 原题
给你一个整数数组 nums
,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
子数组 是数组的连续子序列。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: nums = [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
提示:
1 <= nums.length <= 2 * 10(4)
-10 <= nums[i] <= 10
nums
的任何前缀或后缀的乘积都 保证 是一个 32-位 整数
链接:https://leetcode.cn/problems/maximum-product-subarray/description/
# 解法
题目中的给定的输入是整数数组,里面的元素只有三种:负整数、正整数、以及0。 我们都知道: a.0乘任何数都等于0。 b.而负整数或正整数乘任何一个非0整数I,结果的绝对值都会大于I。
根据a.假如我们选定的子序列中只要有元素是0,所得的结果都会是0。 根据b.不包含0的子序列,元素越多乘积的绝对值越大。 我们可以看作,0把数组截断了,这样的话,子序列就有这两种: 1)[0] 2)被0截断后,正整数和负整数组成的最长子序列
毫无疑问,情况1)的乘积是0。 但情况2)的乘积却是有正有负的: 当2)的乘积是正数或者只有一个元素时,毫无疑问,此子序列的最大乘积就是它。 当2)的乘积是负数并且元素有2个以上时,设子序列的乘积是P,算出X = E1 * E2 * E3 * ... * En(En是子序列中第一个负整数), Y = Em * Em+1 * ... * Ek (Em为子序列中最后一个负整数,k为子序列最后一个元素) 假如|X| < |Y|, 最大的乘积是P/X,反之是P/Y。
实现的时候,其实我们并不需要计算Y的值,因为我们从左往右遍历的时候会顺便把P/Y的值计算出来(假如P是负数的话)。
public int maxProduct(int[] nums) {
int result = -2147483648; //记录结果
int product = 0;
int negative = 0; //上文中的X
boolean negativeInit = false; //用来标记,这段子序列中,是否包含负数
for(int i = 0; i < nums.length; i ++) {
if(product == 0) { //遇到0就重新初始化
negativeInit = false;
product = 1;
}
product *= nums[i];
if(product > result) {
result = product;
}
if (negativeInit && product / negative > result) {
result = product / negative; //上文中的P/X
}
if(product < 0 && !negativeInit) {
negativeInit = true;
negative = product;
}
}
return result;
}
时间复杂度和空间复杂度均为O(n)。
链接:https://leetcode.cn/problems/maximum-product-subarray/solutions/29693/yi-chong-fei-chang-zhi-guan-si-lu-by-wu-di-lin-ge-/