zoukankan      html  css  js  c++  java
  • LeetCode-152-乘积最大子数组

    LeetCode-152-乘积最大子数组

    题目

    给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

    示例 1:
    
    输入: [2,3,-2,4]
    输出: 6
    解释: 子数组 [2,3] 有最大乘积 6。
    
    示例 2:
    
    输入: [-2,0,-1]
    输出: 0
    解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
    

    思路

    这道题乍一看很简单,和之前最最大子数组之和一样,我很轻松的列出了状态转移方程:

    [dp[i]=max(dp[i-1]*x,x); ]

    提交之后发现在自己错的离谱,问题就出在正数和负数上,这里的负数与负数相乘会得到更大的正数;

    也就是说如果在前一个点保存的最大正数,当后面为负数的时候,正数反而没有用了,需要负数来相乘;

    一开始我没有意识到问题的复杂性,自己做了一堆if语句来尝试解决这个问题,结果只能通过前面的简单的用例;

    后面复杂的就不能通过了;

    实在没有办法了,写了一个O(N^2)的暴力代码,结果当输入数据过大的时候超时了;

    万般无奈就去看了题解,发现我就是题解中说明的典型错误示范。。。题解的正确思路是这样的:

    我们可以根据正负性进行分类讨论。
    
    考虑当前位置如果是一个负数的话,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。于是这里我们可以再维护一个 fmin⁡(i),它表示以第 i 个元素结尾的乘积最小子数组的乘积,那么我们可以得到这样的动态规划转移方程:
    
    

    [egin{array}{l}{f_{max }}(i) = mathop {max }limits_{i = 1}^n { {f_{max }}(i - 1) imes {a_i},{f_{min }}(i - 1) imes {a_i},ai} \{f_{min }}(i) = mathop {max }limits_{i = 1}^n { {f_{max }}(i - 1) imes {a_i},{f_{min }}(i - 1) imes {a_i},ai} end{array} ]

    看了人家的思路,顺便就看到了代码,果然还是官方的思路厉害,感觉自己还是太菜了。。

    代码

    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());
        }
    };
    
    
  • 相关阅读:
    12.数组三--数组的冒泡排序与快速排序
    11.数组二
    10.数组一
    Vue之组件与父子传值
    Django模型层
    面向对象的组合用法
    面向对象初识
    Python内置函数
    列表推导式,生成器表达式
    装饰器进阶
  • 原文地址:https://www.cnblogs.com/sakurapiggy/p/13056171.html
Copyright © 2011-2022 走看看