题目链接
题目描述
给你一个整数数组 nums
,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
解题思路
方法一:动态规划
考虑当前位置如果是一个负数的话,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。于是这里我们可以再维护一个 fmin(i),它表示以第 i 个元素结尾的乘积最小子数组的乘积,那么我们可以得到这样的动态规划转移方程:
它代表第 i 个元素结尾的乘积最大子数组的乘积 fmax(i),可以考虑把 a_i 加入第 i−1 个元素结尾的乘积最大或最小的子数组的乘积中,二者加上 a_i ,三者取大,就是第 i 个元素结尾的乘积最大子数组的乘积。第 i 个元素结尾的乘积最小子数组的乘积 fmin(i) 同理。
class Solution {
public int maxProduct(int[] nums) {
int[] Fmax = new int[nums.length];
int[] Fmin = new int[nums.length];
Fmax[0] = Fmin[0] = nums[0];
int ans = Fmax[0];
for(int i = 1; i < nums.length; ++i){
Fmax[i] = Math.max(Fmax[i-1] * nums[i], Math.max(Fmin[i-1] * nums[i], nums[i]));
Fmin[i] = Math.min(Fmax[i-1] * nums[i], Math.min(Fmin[i-1] * nums[i], nums[i]));
ans = Math.max(ans, Fmax[i]);
}
return ans;
}
}
空间优化后
class Solution {
public int maxProduct(int[] nums) {
int Fmax = nums[0];
int Fmin = nums[0];
int ans = nums[0];
int tmp = 0;
for(int i = 1; i < nums.length; ++i){
tmp = Fmax;
Fmax = Math.max(Fmax * nums[i], Math.max(Fmin * nums[i], nums[i]));
Fmin = Math.min(tmp * nums[i], Math.min(Fmin * nums[i], nums[i]));
ans = Math.max(ans, Fmax);
}
return ans;
}
}
- 时间复杂度 O(n)
- 空间复杂度 O(n) 空间优化后为O(1)