1、Description
2、题解思路
对于该问题,需要与之前的最大子段和进行区别,最大值段和产生以nums[i]元素结尾的局部最大值maxVal[i]的时候,只需要获取maxVal[i-1]+nums[i]和nums[i]之间的较大值即可。而该问题为最大子段乘积问题,如果所给的数全都为正整数,那么其递推方程的定义与最大子和是一样的,只不过把加号换成了乘号,然而对于该问题所给的元素也有可能是负数,所以需要考虑负数乘以负数有可能会产生更大的数的情况,为此除了维护一个以nums[i]为结尾元素的当前最大值maxCur之外,还需要维护一个以nums[i]为结尾元素的当前最小值minCur来解决负负得正的问题。而对于每一步中maxCur的更新过程如下:
m
a
x
C
u
r
[
i
]
=
M
a
x
n
u
m
s
[
i
]
,
M
a
x
(
m
a
x
C
u
r
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
m
i
n
C
u
r
[
i
−
1
]
∗
n
u
m
s
[
i
]
)
maxCur[i]=Max{nums[i],Max(maxCur[i-1]*nums[i],minCur[i-1]*nums[i])}
maxCur[i]=Maxnums[i],Max(maxCur[i−1]∗nums[i],minCur[i−1]∗nums[i]),不难理解对于每一步的以nums[i]为结尾元素的最大值有三种情况可以产生①前一步的最大值乘以当前值②前一步的最小值乘以当前值(负负得正的情况)③只有当前值(比如maxCu[i-1]和minCur[i-1]均为负数,而nums[i]为正数时)。同理minCur的更新过程如下所示:
m
i
n
C
u
r
[
i
]
=
M
i
n
n
u
m
s
[
i
]
,
M
i
n
(
m
a
x
C
u
r
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
m
i
n
C
u
r
[
i
−
1
]
∗
n
u
m
s
[
i
]
)
minCur[i]=Min{nums[i],Min(maxCur[i-1]*nums[i],minCur[i-1]*nums[i])}
minCur[i]=Minnums[i],Min(maxCur[i−1]∗nums[i],minCur[i−1]∗nums[i])
对于所给的测试用例nums=[2,3,-2,4]的求解过程如下所示
求解 | maxCur | minCur | result |
---|---|---|---|
step0 | 2 | 2 | 2 |
step1 | 6 | 3 | 6 |
step2 | -2 | -12 | 6 |
step3 | 4 | -48 | 6 |
3、代码实现(java)
这里由于我们每一步只需要用到上一步的极小值以及极大值因此分别各只用一个变量进行存储即可。
class Solution {
public int maxProduct(int[] nums) {
int minCur = nums[0];
int maxCur = nums[0];
int result = nums[0];
for(int i=1;i<nums.length;i++){
int tmp = maxCur;
maxCur = Math.max(Math.max(maxCur*nums[i],minCur*nums[i]),nums[i]);
minCur = Math.min(Math.min(tmp*nums[i],minCur*nums[i]),nums[i]);
result = Math.max(result,maxCur);
}
return result;
}
}