05.18 leetcode每日一题——152. 乘积最大子数组

题目

在这里插入图片描述

解法一 前缀积

思路:
与求前缀和的思路类似,用一个数组保存前缀积
但是由于0的存在,我们将所有的数组按照0分隔开

因为 a*1=a的特殊性. 且是整数数组. 所以在非0数组中,我们可以知道前缀积的绝对值是在增大的。所以子数组越长,子数组的积的绝对值就越大。
我们对于当前数组a0-aj的前缀积a有如下判断:
(1)如果前缀积a的绝对值大于0.那么该前缀的任意子数组的前缀积都小于等于a.所以我们直接返回a即可。
(2)如果前缀积a的绝对值小于0.我们要做的便是找出一个前缀积小于0的最短子数组a0-ai。因为a0-i越短,意味着ai-aj越长,且因为a0-ai的前缀积<0.所以ai-aj的前缀积>0,且越长前缀积越大。

代码

//还是要发掘 题目中的信息。这道题是前缀积,其实最主要还是符号的判断。

class Solution {
//与最大连续子数组的和类似。但是因为这里有0,所以按照0将数组分割为数个小数组,依次求每个小数组的乘积最大子数组。
//因为是一个整数的乘积,所以不含0的话,绝对值一定是越来越大.其实只需要判断正负号。。。
public:
    int maxProduct(vector<int>& nums) {

        bool first=true;    //是否为非0数组的第一个元素
        bool haveZero=false;
        vector <int>muti;     //依次放入非0元素的前缀积。
        int max=-65535;
        for(int i=0;i<nums.size();i++){
            //将非0的进入数组,计算此时的乘积最大子数组。
            if(nums[i]!=0){
                //前缀积的加入
                muti.push_back(first?nums[i]:muti.back()*nums[i]);
                first=false;
                //当前的最大下标
                int now_muti_index=muti.size()-1;
                //求以now_muti_index为下标结尾的该被0分隔后的子数组的最大子数组积。

                //如果前缀积>0.判断直接返回即可。
                if(muti[now_muti_index]>max) max=muti[now_muti_index];
                //最后前缀积<0,向前找第一个为负数的前缀积.
                else {
                    //否则是指定位置的前缀积相除 
                    for(int j=-1;j<now_muti_index-1;j++){
                        int tmp_muti=muti[j+1]; 
                        if(tmp_muti>0) continue;
                        //第一个为负数的前缀积
                        if ((muti[now_muti_index] / tmp_muti) > max ){
                            max=muti[now_muti_index] / tmp_muti;
                        }
                        break;
                    }
                }
            }
            //遇到了0,分隔数组。
            else {
                first=true;
                muti.clear();
                haveZero=true;
            }
        }
        if(haveZero) return max>0?max:0;
        else return max;
    }
};

解法二 动态规划(copy)

这个解法是copy的官方解法.也是利用了正负性的原理来展开的。

这个转移方程是真的牛(我还没接触过dp),通过和ai本身取大.避免开了0对整个数组带来的影响。遇到0时f(max)=f(min)=0. 0之后就又重新展开了.不得不说,牛p.
在这里插入图片描述

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());
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-product-subarray/solution/cheng-ji-zui-da-zi-shu-zu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值