力扣152. 乘积最大子数组

题目

力扣152. 乘积最大子数组_第1张图片
链接:152. 乘积最大子数组

总结

枚举

  1. 看到题目首先就想到了之前做的这个题目(力扣 560. 和为K的子数组),一个是求和一个是求乘积,于是我按照之前的思路敲了一遍。
  2. 心怀着可以一次就能提交成功的不可思议,提交,果然错了,hhh,意料之中。报错的实例是:力扣152. 乘积最大子数组_第2张图片
    忘记考虑只有一个输入并且还是负数的情况了。
    于是最后的代码就变成下面这样啦!
int maxProduct(vector<int>& nums) {
        int sum = 1;//记录乘积
        int max = 0;//记录最大乘积
        if(nums.size() == 1) return nums[0];
        for(int i = 0; i < nums.size(); i++){
            sum = 1;
            for(int j = i; j >= 0; j--){
                sum = sum * nums[j];
                if(sum > max){
                    max = sum;
                }
            }
        }
        return max;
    }

时间复杂度应该是O(n^2)吧!

动态规划

  1. 因为用枚举运行出来耗费的时间有点长,我就抱着应该会有更简单的方法的希望去看了题解,用的是动态规划。
  2. 题解的方法就是利用前面数的最大乘积乘以当前数,然后取乘积和当前数中的较大值,记录在一个数组中,最后取出这个数组中的最大值。状态转移方程为:
    状态转移方程1
  3. 但是这样会出现一个问题,比如[5 , 6 , -1 , 2 , -4],按照上面的步骤,得到的数组就是[5 , 30 , -1 , 2 , -4],最后得到的结果就是30,但是实际上最大的应该是240。
  4. 出现问题的主要原因就是当碰到乘积与负数相乘时,保留的最大值为该负数,本来为负数的乘积与后面 的负数负负得正之后能得到最大值,但是中间负数就给拦截了。那我们是不是可以用两个数组,一个记录当前乘积的最大值,一个记录当前乘积的最小值。然后再进行求解呢?于是就有了下面的状态转移方程:
    力扣152. 乘积最大子数组_第3张图片
    代码也就是这样了:
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        vector <int> maxF(nums), minF(nums);
        for (int i = 1; i < nums.size(); ++i) {
            maxF[i] = max(maxF[i - 1] * nums[i], max(nums[i], minF[i - 1] * nums[i]));
            minF[i] = min(minF[i - 1] * nums[i], min(nums[i], maxF[i - 1] * nums[i]));
        }
        return *max_element(maxF.begin(), maxF.end());
    }
};

这样的时间复杂度是O(n),空间复杂度也是O(n)。

  1. 能不能降低空间复杂度呢?可以的,我们其实只需要记录在遍历过程中的最大乘积就OK了。根本不需要用数组来进行存放。
    于是最后的代码就是这样的了:
int maxProduct(vector<int>& nums) {
        int ans = nums[0];
        int len = nums.size();
        //maxF用来保存遍历到某一遍时的乘积最大值,minF相反
        int maxF = nums[0], minF = nums[0];
        int mx,mn;
        for(int i = 1; i < len; i++){
            int mx = maxF, mn = minF;
            maxF = max(mx * nums[i] , max(mn * nums[i],nums[i]));
            minF = min(mn * nums[i] , min(mx * nums[i],nums[i]));
            ans = max(maxF,ans);//用ans记录遍历到这一遍时前面所有情况中出现的最大乘积
        }
        return ans;
    }

思考

我现在做算法题就是应该先是能做出来,然后再抱着降低时间空间复杂度的想法去找更好的方法来解题。
动态规划的问题还得多多去思考,总会绕不过来。

你可能感兴趣的:(#,枚举,#,动态规划,数据结构与算法)