- Maximum Product Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest product.
Example
Example 1:
Input:[2,3,-2,4]
Output:6
Example 2:
Input:[-1,2,4,1]
Output:8
解法1:
思路: DP。因为数组中可能有正有负或0。用两个数组dpPosMax[]和dpNegMin[] 分别存储正的最大值和负的最小值。
- 当nums[0]>0时,dpPosMax[0]=nums[0], dpNegMin[0]=0,当nums[0]<0时,dpNegMin[0]=nums[0], dpPosMax[0]=0。
- 遍历数组,当nums[i]>0时,
更新dpPosMax[i]: 因为dpPosMax[i]可能为正或0,当为正时,更新为dpPosMax[i - 1] * nums[i] ,因为nums[i]>=1,所以乘积肯定>=dpPosMax[i-1]; 当为0时,更新为nums[i]即可。
更新dpNegMin[i]: 因为dpNegMin[i]可能为负或0,当为负时,更新为dpNegMin[i-1]*nums[i],因为nums[i]>=1,所以乘积肯定更小 ;当为0时,更新为nums[i]即可。
dpPosMax[i] = dpPosMax[i - 1] > 0 ? dpPosMax[i - 1] * nums[i] : nums[i];
dpNegMin[i] = dpNegMin[i -1] < 0 ? dpNegMin[i - 1] * nums[i] : 0; - 对于nums[i]<0的情形类似2)
- 当nums[i]==0时,dpPosMax[i]和dpNegMin[i]都为0。因为已经初始化为0了,所以不用更新。
- 循环中动态更新result。
代码如下:
class Solution {
public:
/**
* @param nums: An array of integers
* @return: An integer
*/
int maxProduct(vector<int> &nums) {
int len = nums.size();
if (len == 0) return 0;
vector<int> dpPosMax(len, 0);
vector<int> dpNegMin(len, 0);
int result = nums[0];
if (nums[0] > 0) {
dpPosMax[0] = nums[0];
}
if (nums[0] < 0) {
dpNegMin[0] = nums[0];
}
for (int i = 1; i < len; ++i) {
if (nums[i] > 0) {
dpPosMax[i] = dpPosMax[i - 1] > 0 ? dpPosMax[i - 1] * nums[i] : nums[i];
dpNegMin[i] = dpNegMin[i -1] < 0 ? dpNegMin[i - 1] * nums[i] : 0;
} else if (nums[i] < 0) {
dpPosMax[i] = dpNegMin[i - 1] < 0 ? dpNegMin[i - 1] * nums[i] : 0;
dpNegMin[i] = dpPosMax[i - 1] > 0 ? dpPosMax[i - 1] * nums[i] : nums[i];
}
result = max(result, dpPosMax[i]);
}
return result;
}
};
解法2:由解法1看出dpPosMax[i]和dpNegMin[i]都只取决于前面一个元素,所以采用滚动数组各用2个变量就可以了。
代码如下:
注意:因为posMaxNew/negMinNew没有缺省值,所以当nums[i]==0时,需要将它们设置为0。
class Solution {
public:
/**
* @param nums: An array of integers
* @return: An integer
*/
int maxProduct(vector<int> &nums) {
int len = nums.size();
if (len == 0) return 0;
int posMaxNew = 0, posMaxOld = 0, negMinNew = 0, negMinOld = 0;
int result = nums[0];
if (nums[0] > 0) {
posMaxNew = nums[0];
}
if (nums[0] < 0) {
negMinNew = nums[0];
}
for (int i = 1; i < len; ++i) {
if (nums[i] > 0) {
int posMax = posMaxNew > 0 ? posMaxNew * nums[i] : nums[i];
int negMin = negMinNew < 0 ? negMinNew * nums[i] : 0;
posMaxOld = posMaxNew;
posMaxNew = posMax;
negMinOld = negMinNew;
negMinNew = negMin;
} else if (nums[i] < 0) {
int posMax = negMinNew < 0 ? negMinNew * nums[i] : 0;
int negMin = posMaxNew > 0 ? posMaxNew * nums[i] : nums[i];
posMaxOld = posMaxNew;
posMaxNew = posMax;
negMinOld = negMinNew;
negMinNew = negMin;
} else {
posMaxNew = 0;
negMinNew = 0;
}
result = max(result, posMaxNew);
}
return result;
}
};
二刷:
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
int maxProd = nums[0] > 0 ? nums[0] : 0;
int minProd = nums[0] < 0 ? nums[0] : 0;
int res = nums[0];
for (int i = 1; i < n; i++) {
if (nums[i] > 0) {
maxProd = max(maxProd * nums[i], nums[i]);
minProd = minProd < 0 ? minProd * nums[i] : 0;
} else if (nums[i] < 0) {
int origMaxProd = maxProd;
maxProd = minProd < 0 ? minProd * nums[i] : 0;
minProd = min(origMaxProd * nums[i], nums[i]);
} else {
maxProd = 0;
minProd = 0;
}
res = max(res, maxProd);
}
return res;
}
};
解法3:
参考自网上。因为每次的最大值都是在posMaxNew * nums[i], negMinNew * nums[i],nums[i]中间选,所以可以直接写成
max = max(max(max * nums[i], min * nums[i]),nums[i]);
min = min(min(min * nums[i],temp * nums[i]),nums[i]);
注意:
1) 当nums[i]==0时,max和min都自动清0。
2)一定要事先保存max的值(int temp = max),不然计算min的时候的max已经被更新了。
public class Solution {
/**
* @param nums: An array of integers
* @return: An integer
*/
// Time O(n)
// Space O(1)
public int maxProduct(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int min = nums[0];
int max = nums[0];
int result = nums[0];
for(int i = 1; i < nums.length; i++){
int temp = max;
max = Math.max(Math.max(max * nums[i], min * nums[i]),nums[i]);
min = Math.min(Math.min(min * nums[i],temp * nums[i]),nums[i]);
result = Math.max(result,max);
}
return result;
}
}