数组之乘积最大子数组

LeetCode 152. 乘积最大子数组

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

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

示例 2:

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

解析:
不包含0的情况
1.0 全为正数
这种情况最简单,直接所有结果相乘即可。

2.1 偶数个负数
负负得正,这种情况也直接将结果相乘即可。
2.2 奇数个负数
奇数是2n+1(或者1+2n),这里2n就是2.1中的情况,偶数个负数相乘结果肯定是正数,再把它附近的所有正数连在一起就构成了最大连乘的子区间。现在要解决的问题就是怎么样排除第一个或者最后一个负数,下面的解法比较巧妙。
从左往右乘,从右往左乘,最后两个区间结果的最大值即为所求的最大连乘结果

包含0的情况
同上面一样,分别从左往右以及从右往左连乘,一旦遇到0,那么下一个数就为它本身,表示区间从0处断开。
为什么呢?你想啊,你之前保留连乘的结果,不管正数还是负数,你都希望后面继续有其他正数或者负数能与之相乘,使结果趋于更大。这时候来了个0,连乘更大的希望就瞬间破灭了,一夜回到解放前。那么从下一个数开始,你是选择继续为0呢,还是重拾希望呢?

综上所述:
所有情况都可以通过从左往右连乘和从右往左连乘进行求解:
全为正数或者偶数个负数,从头乘到尾最大
奇数个负数不含0,从左往右乘到最后一个负数的左面为最大值,之后的乘积都为负数;从右往左乘到最前面一个负数的右边为最大值,再往前乘也都为负数;然后比较这两个最大值,选取最大的那一个
含有0的情况,同上,一旦遇到0,需要断开,也就是后面的乘积要重新开始。
可以看到,以上所有情况都可以进行从左往右和从右往左进行连乘,然后求两种方式的最大值,再选取最大的那一个.
好了,看代码

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        nums_reverse = nums[::-1]
        for i in range(1, len(nums)):
            if nums[i - 1] != 0:
                nums[i] *= nums[i - 1]
            if nums_reverse[i - 1] != 0:
                nums_reverse[i] *= nums_reverse[i - 1]
        return max(max(nums), max(nums_reverse))

解法二:
可以观察到,
如果nums[i]<0,那么当前最大值可以由前面的最小值和nums[i]相乘得到,
如果nums[i]>0,那么当前最大值可以由前面的最大值和nums[i]相乘得到,
如果前面为0或者为负数,那么nums[i]可能就是最大值
有点难懂,等吃透了再更新,先放代码.

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        ans = nums[0]
        pre_max = nums[0]
        pre_min = nums[0]
        for num in nums[1:]:
            cur_max = max(pre_max*num, pre_min*num, num) # 保存最大值
            cur_min = min(pre_max*num, pre_min*num, num) # 保存最小值,为下一轮做准备
            ans = max(ans, cur_max) # 更新最大值
            pre_max = cur_max
            pre_min = cur_min
        return ans
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值