Leetcode 152 Maximum Product Subarray

Leetcode 152 Maximum Product Subarray

题目

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1
Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.

Example 2:
Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

思路

第一想法是用sliding window,但是对于中间断开的不好处理,例如 [ 1 , 2 , − 1 , 0 , 3 , 4 ] [1, 2, -1, 0, 3, 4] [1,2,1,0,3,4].
第二想法是利用dp,但是依旧是感觉断开的情况不好处理,如果储存包含 n u m s [ i ] nums[i] nums[i]的最大乘积依旧没有解决问题。

上网查了下以后发现确实是使用dp,中间断开的解决其实很简单,就是取所有 n u m s [ i ] nums[i] nums[i]中的最大值
问题的关键在于导致乘积不连续的关键在于中间含有负数或零,所以还需同时记录包含 n u m s [ i ] nums[i] nums[i]的最小乘积。

递推式

m i n [ i ] = m i n ( m i n [ i − 1 ] ∗ n u m s [ i ] , m a x [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] ) min[i] = min(min[i - 1] * nums[i], max[i - 1] * nums[i], nums[i]) min[i]=min(min[i1]nums[i],max[i1]nums[i],nums[i]),
m a x [ i ] = m a x ( m i n [ i − 1 ] ∗ n u m s [ i ] , m a x [ i − 1 ] ∗ n u m s [ i ] , n u m s [ i ] ) max[i] = max(min[i - 1] * nums[i], max[i - 1] * nums[i], nums[i]) max[i]=max(min[i1]nums[i],max[i1]nums[i],nums[i]),
加入 n u m s [ i ] nums[i] nums[i]比较相当于同时考虑了从自己开始的情况。

代码

public int maxProduct(int[] nums) {
        int[] min = new int[nums.length];
        int[] max = new int[nums.length];
        
        min[0] = nums[0];
        max[0] = nums[0];
        
        int res = nums[0];
        for (int i = 1; i < nums.length; i++) {
            min[i] = Math.min(Math.min(min[i - 1] * nums[i], max[i - 1] * nums[i]), nums[i]);
            max[i] = Math.max(Math.max(min[i - 1] * nums[i], max[i - 1] * nums[i]), nums[i]);
            res = Math.max(res, max[i]);
        }
        return res;
    }

优化

查看了一下0ms解答,代码如下。

public int maxProduct(int[] nums) {
        int product = 1; 
        int maxProduct = Integer.MIN_VALUE;
        
        for (int i = 0; i < nums.length; i++){
            product *= nums[i];
            maxProduct = Math.max(maxProduct, product);
            if (product == 0){
                product = 1;
            }
        }
        
        product = 1; 
        for (int i = nums.length - 1; i >= 0; i--){
            product *= nums[i];
            maxProduct = Math.max(maxProduct, product);
            if (product == 0){
                product = 1;
            }
        }
        return maxProduct;
    }

思考了一下这个是比较类似于sliding window的想法,因为子列中含有0的情况绝对不是最大,所有遇到0就重来,但是如果是负数可能会有负负得正的情况,持续更新。

一开始没有想明白为什么要走两遍,去掉后一遍测试发现以下的test case没有通过:
[ 3 , − 1 , 4 ] O u t p u t : 3 E x p e c t e d : 4 [3, -1, 4] \\ Output: 3 \\ Expected:4 [3,1,4]Output:3Expected:4

当有奇数个负数的时候,product会不断往后乘,maxProduct会一直等待被更新,其实只处理到了奇数个负数的左边部分。
然后又考虑会不会有可能有一种情况最优解在中间,左边右边都走不到呢,例如 [ 1 , 2 , − 1 , 3 , 4 , − 1 , 2 , 3 ] [1, 2, -1, 3, 4, -1, 2, 3] [1,2,1,3,4,1,2,3],发现这时候最优解其实不仅包含了中间部分,还包含了左右两边的负数或者更多,所以该算法结果正确~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值