问题描述:
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.
源码:
受到大佬的启发,从今天开始按照tag刷题。
看到这个题目第一个想法当然就是动态规划。就想到了用一个二维数组dp[i][j]表示第i个元素到第j个资数组的乘积,然后求出最大值,最后结果,超时。最后一个用例没通过。
超时代码
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if(n == 0) return 0;
vector<vector<int>> dp(n+1, vector<int>(n+1, 1));
// int flag = 0; // 记录最小的元素
int result = INT_MIN;
for(int j=1; j<=n; j++){
for(int i=1; i<=j; i++){
if(j-1>=i) dp[i][j] = dp[i][j-1] * nums[j-1];
else dp[i][j] = nums[j-1];
// cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
result = max(result, dp[i][j]);
}
}
return result;
}
};
然后我就想着用一维的动态规划,小编实力太差了,弄了半天也调了,写了一个思路出来。时间和空间都只有可怜的5%。
用dp[i]表示以i结尾的子集的最大乘积大小。index[i]表示该子集的开头的位置,
当nums[i-1]和dp[i-1]都大于0的时候,说明可以直接衔接上,直接相乘;
当nums[i-1]和dp[i-1]都小于0的时候,说明可以直接衔接上,直接相乘,但是此时万一dp[index[i-1]]>=0,也就是dp[i-1]所选定的子集的前一个元素大于0,此时也应该乘上;
当nums[i-1]小于0和dp[i-1]大于0的时候,此时需要考虑dp[i-1]的子集的前一个元素是否小于,若是小于0,则可以直接连接两个子集;
当nums[i-1]小于0和dp[i-1]大于0的其他时候,则需要遍历了;
其他情况,直接等于本身nums[i-1]。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if(n == 0) return 0;
vector<int> dp(n+1, 1);
vector<int> index(n+1, 0);
int result = INT_MIN;
for(int i=1; i<=n; i++){
if(dp[i-1]>0 && nums[i-1]>0){
dp[i] = dp[i-1]*nums[i-1];
index[i] = index[i-1];
}
else if(dp[i-1]<0 && nums[i-1]<0){
dp[i] = dp[i-1]*nums[i-1];
index[i] = index[i-1];
if(index[i-1]>=0 && dp[index[i-1]]>0){
dp[i] *= dp[index[i-1]];
index[i] = index[index[i-1]];
}
}
else if(nums[i-1]<0 && dp[i-1]>0 && index[i-1]-1>=0 && nums[index[i-1]-1]<0){
dp[i] = dp[i-1] * nums[i-1] * nums[index[i-1]-1];
index[i] = index[i-1]-1;
if(dp[index[i-1]-1]>0){
dp[i] *= dp[index[i-1]-1];
index[i] = index[index[i-1]-1];
}
}
else if(nums[i-1]<0 && dp[i-1]>0){
int tmp = dp[i-1], j=0, flag=0;
for(j=index[i-1]; j<i-1; j++){
cout<<nums[j]<<endl;
tmp = tmp/nums[j];
if(nums[j]<0){
flag = 1;
break;
}
}
if(flag){
dp[i] = tmp*nums[i-1];
index[i] = j+1;
}
else{
dp[i] = nums[i-1];
index[i] = i-1;
}
}
else{
dp[i] = nums[i-1];
index[i] = i-1;
}
cout<<dp[i]<<" "<<index[i]<<endl;
result = max(result, dp[i]);
}
return result;
}
};
然而,翻了一下discuss区,这可能就是本垃圾和大佬的差距吧:
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if(n<=0) return 0;
int result=nums[0], max_cur=nums[0], min_cur=nums[0];
for(int i=1; i<n; i++){
int tmp_max = max_cur, tmp_min = min_cur;
max_cur = max(nums[i]*tmp_max, max(nums[i]*tmp_min, nums[i]));
min_cur = min(nums[i]*tmp_max, min(nums[i]*tmp_min, nums[i]));
result = max(result, max_cur);
}
return result;
}
};
为了防止无脑比较,可以采用分类的方式(不过比小编自己的那个简单得多)。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if(n<=0) return 0;
int result=nums[0], max_cur=nums[0], min_cur=nums[0];
for(int i=1; i<n; i++){
if(nums[i]>0){
max_cur = max(max_cur*nums[i], nums[i]);
min_cur = min(min_cur*nums[i], nums[i]);
}
else{
int tmp = max_cur;
max_cur = max(min_cur*nums[i], nums[i]);
min_cur = min(tmp*nums[i], nums[i]);
}
result = max(result, max_cur);
}
return result;
}
};