LintCode----191. 乘积最大子序列

191. 乘积最大子序列

https://www.lintcode.com/problem/maximum-product-subarray/

求最值,用动态规划解题。 

 

解题步骤:

1. 确定状态: (但凡动规,都要开辟数组存下当前状态。递归则不需要存状态,因为它每次递归都会重新计算,所以运算量远远大于动规解法)因为要求乘积最大,可以开个一维数组res[], res[i]保存当前数组nums[0....i]从下标0到i的乘积最大值

- 最后一步

       res[n-1]保存的是最后一步计算的最终结果

- 子问题

     不考虑最后一个值nums[n-1],子问题变成求nums[0,....n-2]连续子序列的乘积最大

 

2. 转移方程:

      考虑最后一步res[n-1]和res[n-2]之间的关系如何?

      最后一步是不是要考虑算上nums[n-1]的时候,就是从nums[0...n-1]的连续最大乘积,与之前res[n-2]结果比较,取较大的值:

       res[n-1] = max{    res[n-2]  ,    连续序列nums[0...n-1]乘积最大值   }

 

3. 注意边界值和条件:

     数组下标是从0 ---- n-1,

    初始值:res[0] = nums[0],

     连续序列nums[0...n-1]乘积最大值: 可以让maxValue存,从nums[n-1]乘到nums[0]之间的最大值。(这步骤可以考虑优化)

 

4.  计算顺序:

    由转移方程可以知道,要想知道res[n-1],必须先计算res[n-2],所以顺序从res[0]开始算到res[n-1]。 最终返回res[n-1]的值即可。

 

写代码求解:

public class Solution {
    /**
     * @param nums: An array of integers
     * @return: An integer
     */
    public int maxProduct(int[] nums) {
        // write your code here
        int len = nums.length;
        int[] mult = new int[len];
        mult[0] = nums[0]; //初始化
       
        
        for(int i = 1; i < len; i++){
            int maxValue = nums[i]; //包含nums[i]的乘积最大子序列
            int multRes = nums[i];
            for(int j=i-1;j>=0;j--){
                multRes *= nums[j];
                if(multRes>maxValue){
                    maxValue = multRes;
                }
            }
            
            mult[i] = Math.max(mult[i-1],maxValue);
        }
        
        return mult[len-1];
    }
}

 

可以看到我这种解法,因为求包含nums[i]的最大子序列乘积,

用一个for循环求解还是挺耗时的,感觉可以从这边入手考虑优化。 

我这个解法耗时O(n^2)

各位可以想想怎么优化吧

 

参看九章官网题解:

这个解法耗时O(n),

开辟了两个数组,分别存当前乘积最大值和最小值,来应对负数情况,思路挺不错的:

max[i]数组,存的是包含当前nums[i]的序列最大乘积,

min[i]数组,保存的是当前nums[i]的序列最小乘积,

用result来保存当前子序列的最大乘积值。

当nums[i]==0时,考虑,因为0乘任何数都是0。

 

转移方程:

          min[i] = max[i] = nums[i];
          if (nums[i] > 0) {
                max[i] = Math.max(max[i], max[i - 1] * nums[i]);
                min[i] = Math.min(min[i], min[i - 1] * nums[i]);
            } else if (nums[i] < 0) {
                max[i] = Math.max(max[i], min[i - 1] * nums[i]);
                min[i] = Math.min(min[i], max[i - 1] * nums[i]);
            }      

 

举个例子:

  num[2,3,-2, -5,   -4,    2,   0,3,-4,   5,  2,     -1,  -1] ---->得出结果是120

   min[2,3,-12,-5,-240,-480,0,3,-12,-60,-120,-10,-1]

  max[2,6,-2, 60, 20,    40,  0,3,-4,    5, 10,   120,10]

result(2,  6,    6,    60,   60,      60,    60, 60,  60,     60,   60,     120, 120)---->得出结果是120

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值