Leetcode 152:乘积最大子序列(最详细的解法!!!)

给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。

示例 1:

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

示例 2:

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

解题思路

类似问题

Leetcode 53:最大子序和(最详细的解法!!!)

Leetcode 300:最长上升子序列(最详细的解法!!!)

我们直接使用第一个问题中的解法,很快就可得到下面的解。

class Solution:
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.result = nums[0]
        self._maxProduct(nums, len(nums) - 1)
        return self.result

    def _maxProduct(self, nums, index):
        if index == 0:
            return nums[0]

        pre = self._maxProduct(nums, index - 1)
        cur = max(pre*nums[index], nums[index])
        self.result = max(self.result, cur)
        return cur

但是上面这种解法是不正确的,因为我们通过上面的这种解法很容易陷入局部最优解(loc_max)。例如

-1 2 -2

通过上面的算法,只会得到2,实际上最后的结果应该是4

我们要怎么知道全局最大值(glb_max)呢?实际上通过上面的例子我们也能看出些端倪。我们需要维护一个最小值(loc_min),因为如果最小值是一个负数的话,那么最小值乘上一个负数就变成了一个正数,它很能是一个glb_max。那么我们的转移方程就很简单了

  • l o c _ m i n [ i ] = m i n ( l o c _ m a x [ i − 1 ] ∗ n u m s [ i ] , l o c _ m i n [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] loc\_min[i]=min(loc\_max[i-1]*nums[i], loc\_min[i-1]*nums[i], nums[i] loc_min[i]=min(loc_max[i1]nums[i],loc_min[i1]nums[i],nums[i]
  • l o c _ m a x [ i ] = m a x ( l o c _ m a x [ i − 1 ] ∗ n u m s [ i ] , l o c _ m i n [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] ) loc\_max[i]=max(loc\_max[i-1]*nums[i],loc\_min[i-1]*nums[i], nums[i]) loc_max[i]=max(loc_max[i1]nums[i],loc_min[i1]nums[i],nums[i])

代码如下

class Solution:
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)
        loc_min, loc_max = [0]*nums_len, [0]*nums_len
        loc_min[0] = loc_max[0] = glb_max = nums[0]
        for i in range(1, nums_len):
            loc_min[i] = min(loc_max[i-1]*nums[i], loc_min[i-1]*nums[i], nums[i])
            loc_max[i] = max(loc_max[i-1]*nums[i], loc_min[i-1]*nums[i], nums[i])
            glb_max = max(loc_max[i], glb_max)

        return glb_max

上面的解法其实非常不错了,但是我们依然有更好的,我们可以将空间复杂度降到O(1)

class Solution:
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)
        loc_min, loc_max = [0]*2, [0]*2
        loc_min[0] = loc_max[0] = glb_max = nums[0]
        for i in range(1, nums_len):
            loc_min[1] = min(loc_max[0]*nums[i], loc_min[0]*nums[i], nums[i])
            loc_max[1] = max(loc_max[0]*nums[i], loc_min[0]*nums[i], nums[i])
            loc_min[0], loc_max[0] = loc_min[1], loc_max[1]
            glb_max = max(loc_max[1], glb_max)

        return glb_max

一个非常hacker的解法。

class Solution:
    def maxProduct(self, A):
        """
        :type nums: List[int]
        :rtype: int
        """
        B = A[::-1]
        for i in range(1, len(A)):
            A[i] *= A[i - 1] or 1
            B[i] *= B[i - 1] or 1
        return max(A + B)

reference:

https://leetcode.com/problems/maximum-product-subarray/discuss/183483/Easy-and-Concise-Python

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

你可能感兴趣的:(Problems,leetcode解题指南)