Leetcode 152. Maximum Product Subarray

来源:互联网 发布:太空工程师 编程 编辑:程序博客网 时间:2024/05/02 01:53

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.

s思路:
1. 先假设一些理想情况,当都是正数,最大积就是全部数相乘;如果有偶数个负数,也是全部相乘;如果有奇数个负数,那就要比较大小了,例如:nums=[-5,2,3,2-2,-4,2],就需要比较最左边的负数与它之前的正数之积,即:-5,和最右边的负数与它之后的正数之积,即:-4*2=-8,谁绝对值大,就那一边。这里就是:-5之后的所有数相乘即是最大积。
2. 目前为止,我们只讨论了正负数,还没有讨论0的情况。如果含有0,如何处理呢?想了一下,0的作用就是把这个序列分割成左右两个array。所以,需要分别按照上面的方法求最大值,然后比较选出较大的最大值即可!
3. 也就是说,这个题有o(n)的解法,因为每个数最多访问一次即可!
4. 上面的方法是可行,但写起来很复杂,也不好理解。我们换一个角度重新思考。从左往右遍历,我们计算包含当前正在遍历的数的最大乘积和最小乘积,为什么要最小值呢?因为最小值,如果是负数,那么乘以一个负数,就是最大值了。但这个最小值和最大值每次和当前的数相乘是注意,如果当前数是正数,就是最大值乘以当前值仍然是最大值,最小值乘以当前值仍是最小值;如果当前值是负数,那么最大值就是之前的最小值乘这个负数,最小值就是之前的最大值乘这个负数;这还没完,关键的一步是:得到最大最小值,还需要检查是否最大最小,如果当前的遍历的数比最大值还大或比最小值还小,那么就要更新最大值和最小值了,保证是最大值。
5. 上面的思路就是DP思路,就是一路记录包含当前遍历的数的最大乘积和最小乘积,然后取最大乘积的最大值即可!

num -5 2 3 -2 -4 2 curmx -5 2 6 60 48 96 curmn -5 -10 -30 -12 -240 -480

6.问题来了,为什么这个方法比之前枚举各种可能性的简洁,而且好理解呢?这个方法是后面想到的,自己也想过要找最大值、最小值,但是没定义清楚,比如:我们最后需要的最大最小值是包含当前num[i]的最大最小值,而不是从左往右一直乘的最大最小值。这两者的区别是,前者在每次最大最小值,同时考虑了当前值是否比从左往右迭代过来的值还大或还小,由于每次算最大最小值,都考虑了这个信息,所以可以一直保证得到包含目前num[i]的最大最小值。而这个最大值的最大值即使所求!
7. 之前想的第一种方法,只考虑了现象,试图用代码去模拟这个现象,还没抓住本质,因此深入不够,没有一个抽象的点在里面。而后面的方法,就是求包含num[i]的最大最小值,这就是把一个大的目标分割成小的目标,然后我们一直在这个小目标用功,大的目标也就得到了!本质是问题的分割,由于问题可以分割,所以必然是dp.

class Solution {public:    int maxProduct(vector<int>& nums) {        //        int n=nums.size();        int curmx=nums[0];        int curmn=nums[0];        int res=nums[0];        for(int i=1;i<nums.size();i++){            if(nums[i]>0){                curmx*=nums[i];                curmn*=nums[i];            }else{                int tmp=curmx;                curmx=curmn*nums[i];                curmn=tmp*nums[i];            }            curmx=nums[i]>curmx?nums[i]:curmx;            curmn=nums[i]<curmn?nums[i]:curmn;            res=max(res,curmx);                 }        return res;    }};
0 0
原创粉丝点击