• Medium | LeetCode 152. 乘积最大子数组 | 动态规划


    152. 乘积最大子数组

    给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

    示例 1:

    输入: [2,3,-2,4]
    输出: 6
    解释: 子数组 [2,3] 有最大乘积 6。
    

    示例 2:

    输入: [-2,0,-1]
    输出: 0
    解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
    

    解题思路

    此题的问题在于数组中存在负数的情况。负数让普通的动态规划没法处理。

    解决办法是维护两个动态规划数组。类似于 LeetCode 309. 最佳买卖股票时机含冷冻期 | 动态规划(状态机) 维护了三个数组。

    考虑当前位置如果是一个负数的话,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。于是这里我们可以再维护一个
    ${f_{min }}(i) $,它表示以第 ii 个元素结尾的乘积最小子数组的乘积,那么我们可以得到这样的动态规划转移方程:

    [egin{array}{l} f_{max }(i)=max _{imath=1}^{n}left{f_{max }(i-1) imes a_{i}, f_{min }(i-1) imes a_{i}, a_{i} ight} \ f_{min }(i)=min _{imath=1}left{f_{max }(i-1) imes a_{i}, f_{min }(i-1) imes a_{i}, a_{i} ight} end{array} ]

    public int maxProduct(int[] nums) {
        int[] maxDp = new int[nums.length];
        int[] minDp = new int[nums.length];
        maxDp[0] = minDp[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            maxDp[i] = maxInThree(nums[i], nums[i] * maxDp[i-1], nums[i] * minDp[i-1]);
            minDp[i] = minInThree(nums[i], nums[i] * maxDp[i-1], nums[i] * minDp[i-1]);
        }
        int ans = maxDp[0];
        for (int i = 0; i < maxDp.length; i++) {
            ans = Math.max(ans, maxDp[i]);
        }
        return ans;
    }
    
    public int maxInThree(int a, int b, int c) {
        return Math.max(Math.max(a, b), c);
    }
    
    public int minInThree(int a, int b, int c) {
        return Math.min(Math.min(a, b), c);
    }    
    
  • 相关阅读:
    SQL Server 2005 学习笔记之触发器简介[转]
    什么是BCD 码
    关于C# 中的Attribute 特性
    也谈Asp.net 中的身份验证
    SQL Server 2005 创建分区表
    使用SerialPort 对象实现串口拨号器通信[下]
    子角色权限的实现
    SQL Server 中,实现 varbinary 与 varchar 类型之间的数据转换
    TSQL 常用排名函数
    关于ASP.NET 将数据导出成Excel 的总结[中]
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14364861.html
Copyright © 2020-2023  润新知