题目
Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.
Example 1
Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.
Example 2:
Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
思路
第一想法是用sliding window,但是对于中间断开的不好处理,例如
[
1
,
2
,
−
1
,
0
,
3
,
4
]
[1, 2, -1, 0, 3, 4]
[1,2,−1,0,3,4].
第二想法是利用dp,但是依旧是感觉断开的情况不好处理,如果储存包含
n
u
m
s
[
i
]
nums[i]
nums[i]的最大乘积依旧没有解决问题。
上网查了下以后发现确实是使用dp,中间断开的解决其实很简单,就是取所有
n
u
m
s
[
i
]
nums[i]
nums[i]中的最大值。
问题的关键在于导致乘积不连续的关键在于中间含有负数或零,所以还需同时记录包含
n
u
m
s
[
i
]
nums[i]
nums[i]的最小乘积。
递推式
m
i
n
[
i
]
=
m
i
n
(
m
i
n
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
m
a
x
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
n
u
m
s
[
i
]
)
min[i] = min(min[i - 1] * nums[i], max[i - 1] * nums[i], nums[i])
min[i]=min(min[i−1]∗nums[i],max[i−1]∗nums[i],nums[i]),
m
a
x
[
i
]
=
m
a
x
(
m
i
n
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
m
a
x
[
i
−
1
]
∗
n
u
m
s
[
i
]
,
n
u
m
s
[
i
]
)
max[i] = max(min[i - 1] * nums[i], max[i - 1] * nums[i], nums[i])
max[i]=max(min[i−1]∗nums[i],max[i−1]∗nums[i],nums[i]),
加入
n
u
m
s
[
i
]
nums[i]
nums[i]比较相当于同时考虑了从自己开始的情况。
代码
public int maxProduct(int[] nums) {
int[] min = new int[nums.length];
int[] max = new int[nums.length];
min[0] = nums[0];
max[0] = nums[0];
int res = nums[0];
for (int i = 1; i < nums.length; i++) {
min[i] = Math.min(Math.min(min[i - 1] * nums[i], max[i - 1] * nums[i]), nums[i]);
max[i] = Math.max(Math.max(min[i - 1] * nums[i], max[i - 1] * nums[i]), nums[i]);
res = Math.max(res, max[i]);
}
return res;
}
优化
查看了一下0ms解答,代码如下。
public int maxProduct(int[] nums) {
int product = 1;
int maxProduct = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++){
product *= nums[i];
maxProduct = Math.max(maxProduct, product);
if (product == 0){
product = 1;
}
}
product = 1;
for (int i = nums.length - 1; i >= 0; i--){
product *= nums[i];
maxProduct = Math.max(maxProduct, product);
if (product == 0){
product = 1;
}
}
return maxProduct;
}
思考了一下这个是比较类似于sliding window的想法,因为子列中含有0的情况绝对不是最大,所有遇到0就重来,但是如果是负数可能会有负负得正的情况,持续更新。
一开始没有想明白为什么要走两遍,去掉后一遍测试发现以下的test case没有通过:
[
3
,
−
1
,
4
]
O
u
t
p
u
t
:
3
E
x
p
e
c
t
e
d
:
4
[3, -1, 4] \\ Output: 3 \\ Expected:4
[3,−1,4]Output:3Expected:4
当有奇数个负数的时候,product会不断往后乘,maxProduct会一直等待被更新,其实只处理到了奇数个负数的左边部分。
然后又考虑会不会有可能有一种情况最优解在中间,左边右边都走不到呢,例如
[
1
,
2
,
−
1
,
3
,
4
,
−
1
,
2
,
3
]
[1, 2, -1, 3, 4, -1, 2, 3]
[1,2,−1,3,4,−1,2,3],发现这时候最优解其实不仅包含了中间部分,还包含了左右两边的负数或者更多,所以该算法结果正确~