LintCode 乘积最大子序列 动态规划

题目:原题地址

找出一个序列中乘积最大的连续子序列(至少包含一个数)。

样例

比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6

标签 
 
 
这道题看似求所有的子序列的乘积,似乎可以直接用暴力解,但结果大家肯定知道:超时。
所以我们来分析一下这个题目。
以样例来分析,2,3,-2,4
其实我们只需要计算2*3     2*3*-2*4    -2*4 这三个子序列的大小,即:
1.从第一个位置,到第一次需要转折的位置(出现了乘上新元素,变小了,新元素可能为负数,可能为0)
2.从头乘到尾(有可能负负得正嘛)
3.从转折的位置继续开始上面两个步骤
 
我们用两个数组来记录结果
所以当出现转折的时候,即出现了变小的情况,我们把小的那个数用数组2记下来(有可能后面还会出现负数),这时候原来的数组1可以安心的继续向后面计算了
 
讲解的不是很到位,直接看代码吧:
public int maxProduct(int[] nums) {
        int temMax = nums[0];//用于记录最大的值,每次转折后,可能会有新的最大值,要在之间找最大的
        
        int[] dpMax = new int[nums.length];//记录大值的数组
        dpMax[0] = nums[0];
        int[] dpMin = new int[nums.length];//记录小值的数组
        dpMin[0] = nums[0];
        
        //遍历所有需要考虑的数
        for(int i=1;i<nums.length;i++){
            /**
             * Math.max(nums[i], nums[i]*dpMax[i-1]):
             * 第i个数开始转折,或者不转,取大的那个
             * Math.max(Math.max(nums[i], nums[i]*dpMax[i-1]), nums[i]*dpMin[i-1]);
             * 将上面那个大的那个数,与第i个位置,与小的数的乘积作比较
             */
            dpMax[i] = Math.max(Math.max(nums[i], nums[i]*dpMax[i-1]), nums[i]*dpMin[i-1]);
            
            /**
             * 与上面相似,不过记录的小值
             */
            dpMin[i] = Math.min(Math.min(nums[i], nums[i]*dpMin[i-1]), nums[i]*dpMax[i-1]);
            
            //记录过程中出现的最大值
            if(dpMax[i]>temMax){
                temMax = dpMax[i];
            }
        }
        
        return temMax;
    }

最后来一张ac图吧

 

posted @ 2017-08-25 15:32  夏天的冬天  阅读(158)  评论(0编辑  收藏  举报