2022-11-03 17:05阅读: 21评论: 0推荐: 0

力扣-152-乘积最大的子数组

对于dp[i],

  • 如果nums[i-1]>0,dp[i-1]也>0,那就是dp[i-1]*nums[i-1]
  • 如果<0,>0,那就是nums[i-1]
  • 0,<0,那就是nums[i-1]

  • <0,<0,那就是dp[i-1]*nums[i-1]

同样参考最大子数和,还需要一个额外变量来记录最大的…

int maxProduct(vector<int>& nums) {
int n = nums.size(),maxP = -11;
vector<int> dp(n+1);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
int temp = nums[i - 1] * dp[i - 1];
if (temp > 0) dp[i] = temp;
else dp[i] = nums[i - 1];
maxP = max(maxP, dp[i]);
}
return maxP;
}

但是这么做是错误的,就比如-2,3,-4这个例子,最后以-4结尾的子数组最大乘积是24,而不是-4
它参考的不是上一步的最优解3,而是-2和3的乘积-6,也就是说至少这么照搬定义是不符合“最优子结构”的

瞄了题解的提示

这样定义,关键在于对nums[i-1]正负性的讨论,

  • 如果nums[i-1]>0,那么我们期望结果最大的话,就希望前面最大的正数乘积
  • 如果nums[i-1]<0,那么就期望前面最小的负数乘积
int maxProduct(vector<int>& nums) {
int n = nums.size(),maxP = -11;
vector<int> dp(n+1),minRecord(n+1);
dp[0] = 1,minRecord[0]=1;
for (int i = 1; i <= n; i++) {
if (nums[i - 1] > 0) {
minRecord[i] = min(nums[i - 1], minRecord[i - 1] * nums[i - 1]);
dp[i] = max(dp[i - 1] * nums[i - 1], nums[i - 1]);
}
else {
minRecord[i] = min(nums[i - 1], dp[i - 1] * nums[i - 1]);
dp[i] = max(nums[i - 1] * minRecord[i - 1], nums[i - 1]);
}
maxP = max(maxP, dp[i]);
}
return maxP;
}

这里其实维护了两个dp数组,最大就是我们要要的,只需要再维护一个最小
然后众所周知,一维dp可以空间优化

int maxProduct(vector<int>& nums) {
// 前面赋初值11是不合理的
// 这里的三个nums[0]初值其实都是没必要的,但循环遍历nums是必要的
int maxP = nums[0];
int maxRecord = nums[0], preMax = 1, minRecord = nums[0], preMin = 1;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) {
minRecord = min(nums[i], preMin * nums[i]);
maxRecord = max(preMax * nums[i], nums[i]);
}
else {
minRecord = min(nums[i], preMax * nums[i]);
maxRecord = max(nums[i] * preMin, nums[i]);
}
preMax = maxRecord;
preMin = minRecord;
maxP = max(maxP, maxRecord);
}
return maxP;
}

本题的关键在于需要一个额外的dp辅助数组,本题是经典最大字数和的变形

本文作者:YaosGHC

本文链接:https://www.cnblogs.com/yaocy/p/16855100.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(21)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起