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

传送门

题目分析:按照最大子序列和的想法很容易写出转台转移方程:

$$dp_{max}\left [ i \right ]=max\left ( dp_{max}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$

$dp_{max}\left[ i \right]$表示第$i$个元素结尾的乘积最大子数组的乘积。

乍一看是是对的,但是确有问题,因为忽略了乘法中负负得正的规则。比如$nums=\left \{ 5,6,-3,4,-3 \right \}$。

最后一个$-3$所对应的$dp_{max}$既不是$-3$,也不是$4*(-3)$,而是$5\times 6\times \left ( -3 \right )\times 4\times \left ( -3 \right )$

分类讨论,如果$nums[i]$是正数,那么希望他前一个位置结束的$dp_{max}$是一个正数,并且尽可能的大;反之,希望他前一个位置结束的$dp_{max}$是

一个负数,并且尽可能的小(负得多)。那么更改状态转移方程有:

$$dp_{max}\left [ i \right ]=max\left (dp_{max}[i-1]\ast nums\left [ i \right ], dp_{min}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$

$$dp_{min}\left [ i \right ]=min\left (dp_{max}[i-1]\ast nums\left [ i \right ], dp_{min}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$

#include <algorithm>
using namespace std;

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int num = nums.size();
        vector<int> dp_max(num), dp_min(num);
        dp_max[0] = nums[0];
        dp_min[0] = nums[0];
        for(int i = 1; i < num; 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_min[i - 1]*nums[i], min(dp_max[i - 1]*nums[i], nums[i]));
        }
        return *max_element(dp_max.begin(), dp_max.end());
    }
};

max_element(r, r+6),返回数组r中[0, 6)之间的最大值的迭代器,
使用max_element返回的值减去数组头地址即为该最大值在数组的序号。

为了减少空间复杂度,我们可以用滚动数组来做$dp$:

#include <algorithm>
using namespace std;
//使用滚动数组优化空间
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int dp_max = nums[0], dp_min = nums[0], result = nums[0];
        for(int i = 1; i < nums.size(); i++) {
            int dmax = dp_max, dmin = dp_min;
            dp_max = max(dmax * nums[i], max(dmin * nums[i], nums[i]));
            dp_min = min(dmin * nums[i], min(dmax * nums[i], nums[i]));
            result = max(result, dp_max);
        }
        return result;
    }
};

 

posted @ 2020-08-08 11:43  Peterxiazhen  阅读(148)  评论(0编辑  收藏  举报