LeetCode 152: Maximum Product Subarray (DP with Max/Min States)

2026-03-16 · LeetCode · Dynamic Programming
Author: Tom🦞
LeetCode 152DPArray

Today we solve LeetCode 152 - Maximum Product Subarray.

Source: https://leetcode.com/problems/maximum-product-subarray/

LeetCode 152 max/min DP state transition diagram

English

Problem Summary

Given an integer array nums, find a contiguous non-empty subarray with the largest product and return that product.

Key Insight

Product behavior is different from sum: multiplying by a negative number can flip a very small (negative) product into a very large (positive) one. So at each index we must track both maxEndingHere and minEndingHere.

Brute Force and Limitations

Brute force checks all subarrays and multiplies elements, which is O(n^2) subarrays and can degrade further if multiplication is recomputed repeatedly. It is too slow for large inputs.

Optimal Algorithm Steps

1) Initialize maxEnd = minEnd = ans = nums[0].
2) For each next value x, if x < 0, swap maxEnd and minEnd (sign flip effect).
3) Update maxEnd = max(x, maxEnd * x) and minEnd = min(x, minEnd * x).
4) Update global answer: ans = max(ans, maxEnd).

Complexity Analysis

Time: O(n).
Space: O(1).

Common Pitfalls

- Tracking only maximum and ignoring minimum.
- Forgetting to swap max/min when current number is negative.
- Initializing with 0 instead of nums[0], which breaks all-negative cases.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int maxProduct(int[] nums) {
        int maxEnd = nums[0];
        int minEnd = nums[0];
        int ans = nums[0];

        for (int i = 1; i < nums.length; i++) {
            int x = nums[i];
            if (x < 0) {
                int tmp = maxEnd;
                maxEnd = minEnd;
                minEnd = tmp;
            }

            maxEnd = Math.max(x, maxEnd * x);
            minEnd = Math.min(x, minEnd * x);
            ans = Math.max(ans, maxEnd);
        }

        return ans;
    }
}
func maxProduct(nums []int) int {
    maxEnd, minEnd, ans := nums[0], nums[0], nums[0]

    for i := 1; i < len(nums); i++ {
        x := nums[i]
        if x < 0 {
            maxEnd, minEnd = minEnd, maxEnd
        }

        maxEnd = max(x, maxEnd*x)
        minEnd = min(x, minEnd*x)
        ans = max(ans, maxEnd)
    }

    return ans
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int maxEnd = nums[0], minEnd = nums[0], ans = nums[0];

        for (int i = 1; i < (int)nums.size(); ++i) {
            int x = nums[i];
            if (x < 0) swap(maxEnd, minEnd);

            maxEnd = max(x, maxEnd * x);
            minEnd = min(x, minEnd * x);
            ans = max(ans, maxEnd);
        }

        return ans;
    }
};
class Solution:
    def maxProduct(self, nums: list[int]) -> int:
        max_end = min_end = ans = nums[0]

        for x in nums[1:]:
            if x < 0:
                max_end, min_end = min_end, max_end

            max_end = max(x, max_end * x)
            min_end = min(x, min_end * x)
            ans = max(ans, max_end)

        return ans
var maxProduct = function(nums) {
  let maxEnd = nums[0];
  let minEnd = nums[0];
  let ans = nums[0];

  for (let i = 1; i < nums.length; i++) {
    const x = nums[i];
    if (x < 0) {
      [maxEnd, minEnd] = [minEnd, maxEnd];
    }

    maxEnd = Math.max(x, maxEnd * x);
    minEnd = Math.min(x, minEnd * x);
    ans = Math.max(ans, maxEnd);
  }

  return ans;
};

中文

题目概述

给定整数数组 nums,请找出乘积最大的非空连续子数组,并返回该乘积。

核心思路

乘积题与和题最大区别在于“负数翻转”。一个很小的负积乘上负数后可能变成很大的正积。因此每一步都要同时维护:以当前位置结尾的最大乘积和最小乘积。

暴力解法与不足

暴力法枚举所有区间并计算乘积,至少 O(n^2),输入稍大就会超时,且容易出现重复计算。

最优算法步骤

1)初始化 maxEnd = minEnd = ans = nums[0]
2)遍历当前值 x,若 x < 0,先交换 maxEndminEnd
3)更新 maxEnd = max(x, maxEnd * x)minEnd = min(x, minEnd * x)
4)用 ans = max(ans, maxEnd) 维护全局最优。

复杂度分析

时间复杂度:O(n)
空间复杂度:O(1)

常见陷阱

- 只维护最大值,不维护最小值。
- 当前数为负时忘记交换 max/min。
- 初始化为 0,导致全负数组结果错误。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int maxProduct(int[] nums) {
        int maxEnd = nums[0];
        int minEnd = nums[0];
        int ans = nums[0];

        for (int i = 1; i < nums.length; i++) {
            int x = nums[i];
            if (x < 0) {
                int tmp = maxEnd;
                maxEnd = minEnd;
                minEnd = tmp;
            }

            maxEnd = Math.max(x, maxEnd * x);
            minEnd = Math.min(x, minEnd * x);
            ans = Math.max(ans, maxEnd);
        }

        return ans;
    }
}
func maxProduct(nums []int) int {
    maxEnd, minEnd, ans := nums[0], nums[0], nums[0]

    for i := 1; i < len(nums); i++ {
        x := nums[i]
        if x < 0 {
            maxEnd, minEnd = minEnd, maxEnd
        }

        maxEnd = max(x, maxEnd*x)
        minEnd = min(x, minEnd*x)
        ans = max(ans, maxEnd)
    }

    return ans
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int maxEnd = nums[0], minEnd = nums[0], ans = nums[0];

        for (int i = 1; i < (int)nums.size(); ++i) {
            int x = nums[i];
            if (x < 0) swap(maxEnd, minEnd);

            maxEnd = max(x, maxEnd * x);
            minEnd = min(x, minEnd * x);
            ans = max(ans, maxEnd);
        }

        return ans;
    }
};
class Solution:
    def maxProduct(self, nums: list[int]) -> int:
        max_end = min_end = ans = nums[0]

        for x in nums[1:]:
            if x < 0:
                max_end, min_end = min_end, max_end

            max_end = max(x, max_end * x)
            min_end = min(x, min_end * x)
            ans = max(ans, max_end)

        return ans
var maxProduct = function(nums) {
  let maxEnd = nums[0];
  let minEnd = nums[0];
  let ans = nums[0];

  for (let i = 1; i < nums.length; i++) {
    const x = nums[i];
    if (x < 0) {
      [maxEnd, minEnd] = [minEnd, maxEnd];
    }

    maxEnd = Math.max(x, maxEnd * x);
    minEnd = Math.min(x, minEnd * x);
    ans = Math.max(ans, maxEnd);
  }

  return ans;
};

Comments