来自北大算法课的Leetcode题解:152. 乘积最大子数组

代码仓库Github | Leetcode solutions @doubleZ0108 from Peking University.

  • 解法1(T97% S45%): 如果一个子列中负数有偶数个,那所有数乘起来就是最大值;如果负数有奇数个,那从最左一直乘到最后一个负数最大 或者从右一直乘到最前一个负数最大;但如果出现0就会直接归零。因此这个问题就是被0划分的每个小数组中做负数奇偶的讨论,可以通过dp从左到右 从右到左各做一次,取max(max(左→右), max(右→左))

  • 解法2(T90% S22%): 这题跟300题不一样之处在于,加法如果加上一个负数一定是不好的,所以只累计正数就完了,但对于乘法很可能现在成了个负数,一会还要乘个负数,结果是更大的。所以要分开讨论dp数组的变化

    • 如果当前num[i]>0,则希望前一段的乘积尽可能大
    • 如果当前num[i]<0,则希望前一段的乘积尽可能小

    因此需要定义两个dp数组,dp_max[i]代表以第i个数结尾的连续子数组乘积的最大值,dp_min[i]代表以第i个数结尾的连续子数组乘积的最小值,每次两个dp数组都进行扩展,最后选择dp_max中最大值

    for i in range(1, len(nums)):
        dp_max[i] = max(dp_max[i-1]*nums[i], dp_min[i-1]*nums[i], nums[i])
        dp_min[i] = min(dp_max[i-1]*nums[i], dp_min[i-1]*nums[i], nums[i])
    
class Solution(object):
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        revs = nums[::-1]
        for i in range(1,len(nums)):
            nums[i] *= nums[i-1] if nums[i-1]!=0 else 1     # 如果前一位是0,i就相当于新的开始,这位的dp就是它自己,所以*=1,否则无脑乘上前面就好
        for i in range(1,len(revs)):
            revs[i] *= revs[i-1] if revs[i-1]!=0 else 1

        return max(max(nums), max(revs))

    def otherSolution(self, nums):
        # 解法2
        dp_max = copy.copy(nums)
        dp_min = copy.copy(nums)

        for i in range(1, len(nums)):
            dp_max[i] = max(dp_max[i-1]*nums[i], dp_min[i-1]*nums[i], nums[i])
            dp_min[i] = min(dp_max[i-1]*nums[i], dp_min[i-1]*nums[i], nums[i])

        return max(dp_max)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

doubleZ0108

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值