【两次过】Lintcode 191. 乘积最大子序列

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

样例

样例 1:

输入:[2,3,-2,4]
输出:6

样例 2:

输入:[-1,2,4,1]
输出:8

解题思路1:

常规思路两遍遍历,时间复杂度O(n^2)

public class Solution {
    /**
     * @param nums: An array of integers
     * @return: An integer
     */
    public int maxProduct(int[] nums) {
        // write your code here
        int res = nums[0];
        
        for(int i=0; i<nums.length; i++){
            int temp = 1;
            for(int j=i; j<nums.length; j++){
                temp = temp*nums[j];
                res = Math.max(res, temp);
            }
        }
        
        return res;
    }
}

解题思路2:

动态规划。

  1. 确定状态:
    • 最后一步: 考虑最后一个数A[n], 那么乘积最大的就是前面以n - 1为结尾的最大乘积, 再乘上这个数
    • 在这里要注意, 如果A[n]是个负数, 因为负负得正, 所以我们需要以n - 1为结尾的最小乘积
  2. 转移方程:
    • 维护两个数组, dp1[i] 和 dp2[i], dp1[i]用于记录最大乘积, dp2[i]用于记录最小乘积.
    • A[i]代表数组中的第i个数
    • 转移方程: 截止到i(包括i)为止,最大乘积可能是当前值nums[i],或者前i-1最大值*nums[i],若当前i为负数,而最小值也为负数,还可能是前i-1最小值*nums[i],所以取三个数的最大值。最小值同理

dp1[i] = max(nums[i], dp1[i-1]*nums[i], dp2[i-1]*nums[i]);

dp2[i] = min(nums[i], dp1[i-1]*nums[i], dp2[i-1]*nums[i]);

  1. 初始条件与边界情况:
    • dp1[0] = A[0], dp2[0] = A[0]
  2. 计算顺序:
    • 从左往右
    • 最终结果max(i -> 0...n | dp1[i])
public class Solution {
    /**
     * @param nums: An array of integers
     * @return: An integer
     */
    public int maxProduct(int[] nums) {
        // write your code here
        if(nums == null || nums.length <= 0)
            return 0;
        
        int res = nums[0];
        int[] dp1 = new int[nums.length];   //乘积最大子序列的值
        int[] dp2 = new int[nums.length];   //乘积最小子序列的值
        dp1[0] = nums[0];
        dp2[0] = nums[0];
        
        for(int i=1; i<nums.length; i++){
            dp1[i] = Math.max(nums[i], Math.max(dp1[i-1]*nums[i], dp2[i-1]*nums[i]));
            dp2[i] = Math.min(nums[i], Math.min(dp1[i-1]*nums[i], dp2[i-1]*nums[i]));
        }
        
        for(int i=1; i<dp1.length; i++)
            res = Math.max(res, dp1[i]);
        
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值