数学来辅助做题——乘积最大子数组

多的不说了,和前几天的差不多,直接上题。
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

暴力:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int len=nums.size();
        int pro=nums[0];
        for(int i=0;i<len;i++)
        {
            int p=1;
            for(int j=i;j<len;j++)
            {
                p*=nums[j];
                if(pro<p)
                    pro=p;
            }
        }
        return pro;
    }
};

动态规划:
其实整个乘积数组难就难在负数部分,我们之前的正数在遇到负数后就会变成最小,但是如果后面有负数出现,就又会把结果变成最大。
所以,我们申请两个数组来存取到当前位置的最大值和当前位置的最小值,也就是正数数组将整数变负前的正数存储下来,负数数组把负的数组保存下来,0的情况可涵盖在其中。
但其实我们的乘积是无后效性的,也就是说i位置只和i-1位置的结果有关,所以我们不需要申请一个数组,只需要申请两个数存取i-1的结果就行。
代码就出来了。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int len=nums.size();
        int maxp=nums[0],minp=nums[0],pro=nums[0];
        for(int i=1;i<len;i++)
        {
            int mx=maxp,mi=minp;//因为之后会先更新maxp,所以minp会用更新后的,因此需要提前保存好之前的大小
            maxp=max(mx*nums[i],max(mi*nums[i],nums[i]));//最大更新、最小更新、此数
            minp=min(mi*nums[i],min(mx*nums[i],nums[i]));//最小更新、最大更新、此数
            pro=max(maxp,pro);//更新结果
        }
        return pro;
    }
};

动态规划需要辅助数组来保存结果,上述情况则可以节省空间,因为每一个状态方程只和上一个状态有关,所以只需要保存上个结果即可。也就是无后效性。
数学辅助
这个是我第一下就想起来的方法。
乘积的变化无非是三种情况:

  1. 全正数,越大越好。
  2. 有奇数个负数则为负,偶数个则为正,所以要保证数组内是偶数个负数。
  3. 0,数组内不含0,因为0会让所有的结果失效。

所以,我们将数相乘,用一个数来保存最大结果,随着乘积更新。数组我们以0为分界线,划分为数个子数组,重复上述方法。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int len=nums.size();
        int maxr=nums[0];
        int pro=1;
        for(auto a:nums)
        {
            pro*=a;
            maxr=max(maxr,pro);
            if(pro==0)
                pro=1;
        }
        pro=1;
        for(int i=len-1;i>=0;i--)
        {
            pro*=nums[i];
            maxr=max(maxr,pro);
            if(pro==0)
                pro=1;
        }
        return maxr;
    }
};

还是那句话,数学是基础,编程是工具。
加油。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值