[leetcode]152. Maximum Product Subarray 最大子序列乘积

题目:

Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.

思路:

动态规划。

这道题类似于求最大子序列和。在求最大子序列和时,会比较当前值与当前值加上前面子序列的和,保留较大的一个。而在求最大乘积时,由于0和负数的存在,不能只考虑保留乘积最大的部分,还要考虑保留乘积最小的部分。

代码为:

int maxProduct(vector<int>& nums) {
        if(nums.size()==1)
            return nums[0];
        int n=nums.size();
        vector<int> maxPro(n,0),minPro(n,0);
        maxPro[0]=nums[0];
        minPro[0]=nums[0];
        int res=nums[0];
        for(int i=1;i<n;++i){
            maxPro[i]=max(nums[i],max(nums[i]*maxPro[i-1],nums[i]*minPro[i-1]));
            minPro[i]=min(nums[i],min(nums[i]*maxPro[i-1],nums[i]*minPro[i-1]));
            res=max(res,maxPro[i]);
        }
        return res;
    }

另外一个思路是我自己在做题时想的,比上文提到的思路繁琐,但时间复杂度也为O(n),先记录如下:

思路:

首先把0作为一个分界点,遇到0时,先找到前面序列的最大子序列乘积,在接下来的过程中,前面的子序列不在考虑。

在其中一段子序列中,记录下负数的个数,子序列的乘积tmpPro,从子序列开始到第一个负数的乘积subPro1和从最后一个负数到子序列最后的乘积subPro2,具体例子如下:

序列 -2,3,4,-3,3,1,-5,3

这里tmpPro=-3240,subPro1=-2,subPro2=-5*3=-15。由于负数个数为奇数,就有可能出现第一个负数为分界点和最后一个负数为分界点的情况,这里就需要比较tmpPro/subPro1和tmpPro/subPro2,选择其中最大的子序列乘积。同时这里也需要注意:

1)序列中有0,0等类似的情况,这时tmpPro=1,不能作为子序列的乘积,在这里加入tmpValid标记变量tmpPro是否可用

2)子序列中只有一个负数的情况,如-2,用上面的方法就会出现除数为1的情况,在这里加入subValid标记变量subPro1是否可除

代码:

在这段代码中,可以现在nums后插入0,这样就不用在最后又重复一段代码。

int maxProduct(vector<int>& nums) {
        if(nums.size()==1)
            return nums[0];
        
        int maxPro=nums[0];
        int negNum=0;
        int tmpPro=1;
        int subPro1=1;
        int subPro2=1;
        bool tmpValid=0;
        bool subValid=0;
        for(int i=0;i<nums.size();++i){
            if(nums[i]==0 ){
                if(tmpValid){
                    
                    if(negNum%2==0)
                        maxPro=max(maxPro,tmpPro);
                    else{
                        if (negNum == 1 && !subValid)
                            maxPro = max(maxPro, tmpPro);
                        else
                            maxPro = max(maxPro, max(tmpPro / subPro1, tmpPro / subPro2));
                    }
                }
                maxPro=max(maxPro,0);
                    
                tmpPro=1;
                negNum=0;
                subPro1=1;
                subPro2=1;
                tmpValid=0;
                subValid=0;
            }else{
                tmpPro*=nums[i];
                tmpValid=1;
                if(nums[i]<0){
                    if(negNum==0)
                        subPro1*=nums[i];
                   
                    subPro2=nums[i];
                    negNum++;
                }else{
                    if(negNum==0)
                        subPro1*=nums[i];
                    else
                        subPro2*=nums[i];
                    subValid=1;
                }
            }
        }
        
        if(tmpValid){                    
            if(negNum%2==0)
                maxPro=max(maxPro,tmpPro);
            else{
                if (negNum == 1 && !subValid)
                    maxPro = max(maxPro, tmpPro);
                else
                    maxPro = max(maxPro, max(tmpPro / subPro1, tmpPro / subPro2));
            }
        }
        
        return maxPro;
        
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值