手撸代码系列(十五)--乘积最大子数组

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

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

示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
题目分析:动态规划

     我们先定义一个数组 d p M a x dpMax dpMax,用 d p M a x [ i ] dpMax[i] dpMax[i] 表示以第 i i i 个元素的结尾的子数组,乘积最大的值,也就是这个数组必须包含第 i i i 个元素。

那么 d p M a x [ i ] dpMax[i] dpMax[i] 的取值情况有以下几种:

  1. n u m s [ i ] ≥ 0 nums[i] \ge 0 nums[i]0 并且 d p M a x [ i − 1 ] ≥ 0 dpMax[i - 1] \ge 0 dpMax[i1]0 d p M a x [ i ] = d p M a x [ i − 1 ] ∗ n u m s [ i ] dpMax[i] = dpMax[i - 1] * nums[i] dpMax[i]=dpMax[i1]nums[i]

  2. n u m s [ i ] ≥ 0 nums[i] \ge 0 nums[i]0 并且 d p M a x [ i − 1 ] < 0 dpMax[i - 1] < 0 dpMax[i1]<0,此时如果和前边的数累乘的话,结果会负得更多(即值越小),所以直接将 n u m s [ i ] nums[i] nums[i] 赋值给当前的结果, d p M a x [ i ] = n u m s [ i ] dpMax[i] = nums[i] dpMax[i]=nums[i]

  3. n u m s [ i ] < 0 nums[i] < 0 nums[i]<0,如果前面累乘结果( d p M a x [ i − 1 ] dpMax[i - 1] dpMax[i1]) 是一个负很多的数(即很小的负数), 和当前负数累乘的话( d p M a x [ i − 1 ] ∗ n u m s [ i ] dpMax[i - 1] * nums[i] dpMax[i1]nums[i])就会变成一个更大的正数。因此,还需要一个数组 d p M i n dpMin dpMin 来记录以第 i i i 个元素的结尾的子数组,乘积最小的值。

    d p M i n [ i − 1 ] < 0 dpMin[i - 1] < 0 dpMin[i1]<0 d p M a x [ i ] = d p M i n [ i − 1 ] ∗ n u m s [ i ] dpMax[i] = dpMin[i - 1] * nums[i] dpMax[i]=dpMin[i1]nums[i]
    d p M i n [ i − 1 ] ≥ 0 dpMin[i - 1] \ge 0 dpMin[i1]0 d p M a x [ i ] = n u m s [ i ] dpMax[i] = nums[i] dpMax[i]=nums[i]

d p M i n dpMin dpMin的求解其实和上边求 d p M a x dpMax dpMax 的过程其实是一样的。

我们注意到上边 d p M a x [ i ] dpMax[i] dpMax[i] 的取值无非就是三种, d p M a x [ i − 1 ] ∗ n u m s [ i ] dpMax[i - 1] * nums[i] dpMax[i1]nums[i] d p M i n [ i − 1 ] ∗ n u m s [ i ] dpMin[i - 1] * nums[i] dpMin[i1]nums[i]以及 n u m s [ i ] nums[i] nums[i]

实际计算的时候,只需要从三个取值中选一个最大的即可: d p M a x [ i ] = max ⁡ ( d p M a x [ i − 1 ] ∗ n u m s [ i ] , d p M i n [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] ) dpMax[i] = \max (dpMax[i - 1] * nums[i],dpMin[i - 1] * nums[i],nums[i]) dpMax[i]=max(dpMax[i1]nums[i],dpMin[i1]nums[i],nums[i])

d p M i n dpMin dpMin 同理:
d p M i n [ i ] = min ⁡ ( d p M a x [ i − 1 ] ∗ n u m s [ i ] , d p M i n [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] ) dpMin[i] = \min (dpMax[i - 1] * nums[i],dpMin[i - 1] * nums[i],nums[i]) dpMin[i]=min(dpMax[i1]nums[i],dpMin[i1]nums[i],nums[i])

Java代码:
/**
 * 【题目】: 乘积最大子数组
 * 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子
 * 数组中至少包含一个数字),并返回该子数组所对应的乘积。
 * 
 * 示例 1:
 * 输入: [2,3,-2,4]
 * 输出: 6
 * 解释: 子数组 [2,3] 有最大乘积 6。
 * 
 * 示例 2:
 * 输入: [-2,0,-1]
 * 输出: 0
 * 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。给定一个单链表,编写
一个函数返回该链表的中间点。
 */

public class leetcode_152 {
    /**
     * 动态规划求解 乘积最大的子数组
     * @param nums
     * @return
     */
    public static int maxProduct(int[] nums){
        int n = nums.length;
        if (n==0){
            return 0;
        }
        int[] dpMax = new int[n];
        dpMax[0] = nums[0];
        int[] dpMin = new int[n];
        dpMin[0] = nums[0];
        int max = nums[0];
        for (int i = 1; i < n; i++) {
            dpMax[i] = Math.max(dpMax[i-1]*nums[i], Math.max(dpMin[i-1]*nums[i], nums[i]));
            dpMin[i] = Math.min(dpMax[i-1]*nums[i], Math.min(dpMin[i-1]*nums[i], nums[i]));
            max = Math.max(max, dpMax[i]);
        }
        return max;
    }
    
    public static void main(String[] args) {
        int[] array = {1,4,-6,7,-2,-5, 3,-8,9};
        System.out.println(maxProduct(array));
    }
}

【注】
(1):leetcode 等平台只要我们完成一个函数即可,本人初出茅庐,为了巩固基本知识,故自己补充了部分代码,用于练手。本代码也许存在漏洞,望高手赐教。感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值