力扣工作周刷题 - 152.乘积最大序列和

2020.11.7
原题:点击此处

本道题很明显是一道动态规划的题目。
直接在题目中给出“最大”的词眼。

不过做了两次我还是没有做出来。。

第一次的想法是用一个二维数组去不断根据上一行遍历,但是这样的话会因为出现0,导致代码非常臃肿且易错。

第二次看了题解之后还是错了。
本道题的原处思路是分类讨论,并且分类讨论的情况还比较多的。

首先,我们要建立的DP数组为dpMax[i]
它的含义是 以i为结尾的最大序列和乘积是多少,所以必定是包含nums[i]
以下我们进行分类讨论。
1、当nums[i] >= 0,且dpMax[i-1] >= 0时,dpMax[i] = nums[i] * dpMax[i-1]
2、当nums[i] >= 0dpMax[i-1]<0时,考虑到相乘之后只会越来越小,所以dpMax[i] = nums[i]
3、当nums[i] < 0时,这个条件是让本题变得困难的罪魁祸首。
我们需要得知,在这种情况下,要得到一个最大的数,我们需要前面极可能小的负数相乘,就会得到一个最大的数,因此我们需要额外一个数组dpMin来存储以i结尾的最小序列乘积和是多少。
dpMin[i-1] < 0时,dpMax[i] = dpMin[i-1] * nums[i];
dpMin[i-1] >= 0时,dpMax[i] = nums[i]
4、根据上面的条件,我们知道,如果要写代码进行模拟,将会出现非常多的if和else语句,因此使用技巧观察dpMax,可以得知,无论如何,dpMax都只会在三个值里面取,因此每次都只要比较三个值的大小即可,并且我们可以知道dpMaxdpMin都是只跟前一个数有关,因此可以不用数组,只用常数就可以进行记录。

代码如下:

class Solution {
    public int maxProduct(int[] nums) {
        int imax = 1;
        int imin = 1;
        int max = nums[0];
        for(int i = 0; i<nums.length; i++){
            int preMax = imax;
            imax = Math.max(nums[i],Math.max(imax*nums[i],imin*nums[i]));
            //System.out.println(imax);
            imin = Math.min(nums[i],Math.min(preMax*nums[i],imin*nums[i]));
            //System.out.println(imin);
            max = Math.max(imax,max);
        }
        return max;
    }
}

易错点:
1、忘记写preMax,导致imin的计算出错。
2、max的比较是imax和max,不应该是preMax和imax。
3、imax和imin的初始值应该是1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值