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(i−1)∗ai,fmin(i−1)∗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(i−1)∗ai,fmin(i−1)∗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