タイトルの説明
整数配列numsを与えます。配列内で最大の積を持つ連続サブ配列を見つけてください(サブ配列には少なくとも1つの数値が含まれます)。
例:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
アイデア
これは積であり、配列に正の数と負の数の両方があるため、最大値に負の数を掛けて最小値にし、最小値に負の数を掛けて最大値にする場合があるため、2つのdp配列を維持する必要があります:dpMaxとdpMin、 dpMax [i]はiで終わる最大のシーケンス積で、dpMin [i]はiで終わる最小のシーケンス積です。2つの状況があります。
- nums [i]> = 0の場合:
- dpMax [i] = max(dpMax [i-1] * nums [i]、nums [i]);
- dpMin [i] = min(dpMin [i-1] * nums [i]、nums [i]);
- nums [i] <0の場合:
- dpMax [i] = max(dpMin [i-1] * nums [i]、nums [i]);
- dpMin [i] = min(dpMax [i-1] * nums [i]、nums [i]);
要約すると、次のとおりです。
- dpMax [i] = max(dpMax [i-1] * nums [i]、nums [i]、dpMin [i-1] * nums [i]);
- dpMin [i] = min(dpMin [i-1] * nums [i]、nums [i]、dpMax [i-1] * nums [i]);
対応するコードは次のとおりです。
class Solution {
public:
int maxProduct(vector<int>& nums) {
if(nums.empty()) return 0;
int dpMax[nums.size()], dpMin[nums.size()];
memset(dpMax, 0, sizeof(dpMax));
memset(dpMin, 0, sizeof(dpMin));
int maxPro = nums[0];
dpMax[0] = nums[0];
dpMin[0] = nums[0];
for(int i=1; i<nums.size(); i++){
dpMax[i] = max(max(dpMax[i-1]*nums[i], nums[i]), dpMin[i-1]*nums[i]);
dpMin[i] = min(min(dpMax[i-1]*nums[i], nums[i]), dpMin[i-1]*nums[i]);
maxPro = max(dpMax[i], maxPro);
}
return maxPro;
}
};
- 時間の複雑さ:O(n)
- スペースの複雑さ:O(n)
スペースの複雑さの最適化:
2つの変数の代わりにdp配列を使用できます。コードは次のとおりです。
class Solution {
public:
int maxProduct(vector<int>& nums) {
if(nums.empty()) return 0;
int curMax = nums[0];
int curMin = nums[0];
int maxPro = nums[0];
for(int i=1; i<nums.size(); i++){
int temp = curMax; // 因为curMax在下一行可能会被更新,所以保存下来
curMax = max(max(curMax*nums[i], nums[i]), curMin*nums[i]);
curMin = min(min(curMin*nums[i], nums[i]), temp*nums[i]);
maxPro = max(curMax, maxPro);
}
return maxPro;
}
};
- 時間の複雑さ:O(n)
- スペースの複雑さ:O(1)