Leetcode-152 乘积最大子数组
题目描述
给你一个整数数组nums
,请你找出数组中乘积最大的非空连续
子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例2:
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
link
解题思路
一种错误的解题思路
用dp[i]
表示以第i
个元素结尾的乘积最大子数组
的乘积,你可能会想到这样的转移方程 dp[i] = max(dp[i-1] * nums[i], dp[i-1])
,但是当前位置的最优解未必是由前一个位置的最优解转移得到!比如[3, 4, -2, 7, -1],我们使用上述转移方程,最后的结果是12,实际上应该是3 * 4 * (-2) * 7 * (-1)。
正确的思路(一)
- 当前位置如果是一个负数,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。
- 如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。
于是这里我们可以再维护一个dp(min)[i]
,它表示以第i
个元素结尾的乘积最小子数组的乘积,那么我们可以得到这样的动态规划转移方程:
dp(max)[i] = max(dp(max)[i-1] * nums[i], dp(min)[i-1] * nums[i], nums[i])
,
dp(min)[i] = min(dp(max)[i-1] * nums[i], dp(min)[i-1] * nums[i], nums[i])
C++代码
class Solution {
public:
int maxProduct(vector<int>& nums) {
vector<int> dp_max(nums), dp_min(nums);
for (int i = 1; i < nums.size(); i++) {
dp_max[i] = max(dp_max[i-1] * nums[i], max(dp_min[i-1] * nums[i], nums[i]));
dp_min[i] = min(dp_max[i-1] * nums[i], max(dp_min[i-1] * nums[i], nums[i]));
}
return *max_element(dp_max.begin(), dp_max.end());
}
};
正确的思路(二)
令 imax
为当前最大值, imin
为当前最小值,考虑到 nums[i]
正负的情况,那么最大值res
可以这样求取:
nums[i] > 0
时:imax = max(imax * nums[i], nums[i])
,imin = min(imin * nums[i], nums[i])
nums[i] <= 0
时:imax = max(imin * nums[i], nums[i])
,imin = min(imax* nums[i], nums[i])
在此过程更新最大值res
就可以
C++代码
class Solution {
public:
int maxProduct(vector<int>& nums) {
int res = INT_MIN, imax = 1, imin = 1;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) {
imax = max((imax * nums[i]), nums[i]);
imin = min((imin * nums[i]), nums[i]);
}
if (nums[i] <= 0) {
int tmp = imax;
imax = max((imin * nums[i]), nums[i]);
imin = min((tmp * nums[i]), nums[i]);
}
res = max(res, imax);
}
return res;
}
};
这里,可以进行逻辑的简化:如果 nums[i] < 0
,我将imax 和 imin 互换即可,那么当前最大值和最小值就可以写成一种形式:
class Solution {
public:
int maxProduct(vector<int>& nums) {
int res = INT_MIN, imax = 1, imin = 1;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] < 0) {
int tmp = imax;
imax = imin;
imin = tmp;
}
imax = max((imax * nums[i]), nums[i]);
imin = min((imin * nums[i]), nums[i]);
res = max(res, imax);
}
return res;
}
};
标签:min,152,乘积,nums,max,imin,imax,Leetcode,dp
From: https://blog.csdn.net/weixin_51332735/article/details/139151767