Title

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

示例 1:

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

示例 2:

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

Solve

动态规划

如果当前位置是一个负数的话,那么我们希望在它前面一个位置的某一段的积也是个负数,并且尽可能小,负负得正。

如果当前位置是一个正数的话,那么我们希望它前面一个位置的某一段的积也是个正数,并且希望它尽可能大。

这样,我们可以维护一个fmax(i)和fmin(i),分别表示以第i个元素结尾的最大(小)乘积的子数组的乘积。
f m a x ( i ) = m a x i = 1 n { f m a x ( i − 1 ) ∗ a i , f m i n ( i − 1 ) ∗ a i , a i } f_{max}(i)=max^{n}_{i=1}\{f_{max}(i-1)*a_i,f_{min}(i-1)*a_i,a_i\} fmax(i)=maxi=1n{fmax(i1)ai,fmin(i1)ai,ai} f m i n ( i ) = m i n i = 1 n { f m a x ( i − 1 ) ∗ a i , f m i n ( i − 1 ) ∗ a i , a i } f_{min}(i)=min^{n}_{i=1}\{f_{max}(i-1)*a_i,f_{min}(i-1)*a_i,a_i\} fmin(i)=mini=1n{fmax(i1)ai,fmin(i1)ai,ai}

它代表第i个元素结尾的乘积最大子数组的乘积fmax(i),可以考虑吧ai加入第i-1个元素结尾的乘积最大或最小的子数组的乘积中,二者加上ai,三者取大。

第i个元素结尾的乘积最小子数组的乘积fmin(i)同理。

由于第i个状态只和第i-1个状态有关,根据【滚动数组】思想,可以只用fmax(i)和fmin(i)两个变量来维护i-1时刻的状态。

Code

class Solution:
	def maxProduct(self, nums: List[int]) -> int:
		maxF, minF, ans = nums[0], nums[0], nums[0]
		for i in range(1, len(nums)):
			mx, mn = maxF, minF
			maxF = max(mx * nums[i], max(mn * nums[i], nums[i]))
			minF = min(mn * nums[i], min(mx * nums[i], nums[i]))
			ans = max(ans, maxF)
		return ans