LeetCode 152. 乘积最大子数组(java代码和思路分析)

题目传送门

解题思路:

最原始的想法就是枚举起点终点,然后遍历乘一遍。最终MAX就是答案。
但是这个做法的复杂度达到了O(n^3),很难接受,所以有dp的解法。


dp分析:
考虑集合的表示:
f[i], g[i]
f[i]表示以i为终点,左侧连续且乘积最大的值是多少
g[i]表示以i为终点,左侧连续且乘积最小的值是多少

因为在枚举终点,最优解一定是某个终点向左连续乘积得到的,所以一定可以得到答案。所以f[k]之中最大的那个就是答案。

考虑状态的计算:
我们有了f[i-1], g[i-1],要想办法求出f[i], g[i]
因为左侧都是连续的,所以以第i位结尾的只有三种情况:

  1. 不要前面的数,自己本身,即nums[i]
  2. 如果nums[i]>0,最大值应该是nums[i] * f[i],最小值应该是nums[i] * g[i]
  3. 如果nums[i]<0,最大值应该是nums[i] * g[i],最小值应该是nums[i] * f[i]

本身是正数,不管f[i-1]和g[i-1]是正还是负,肯定要乘最大的才能获得到最大值。负数同理。可以自己找几个数试一下。
根据定义我们只需要把nums[i],nums[i] * f[i],nums[i] * g[i]算出来
最大的就是f[i],最小的就是g[i]
然后找出f的最大值返回即可


我们可以优化空间,因为只和上一位有关,所以数组用一个数记录上一位的f和g即可,每次res和f取一下max。

代码实现:

class Solution {
    public int maxProduct(int[] nums) {
        int len = nums.length;
        int f = nums[0], g = nums[0];
        int res = f;
        for (int i = 1; i < len; i ++ ) {
            int a = nums[i] * f;
            int b = nums[i] * g;
            f = Math.max(nums[i], Math.max(a, b));
            g = Math.min(nums[i], Math.min(a, b));
            res = Math.max(res, f);
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值