LeetCode 0152 - Maximum Product Subarray
- Difficulty: Medium
- Topics: Array, Dynamic Programming, Prefix / Suffix Product
Problem Description
Given an integer array nums, find a contiguous non-empty subarray within the array that has the largest product, and return the product.
The test cases are generated so that the answer will fit in a 32-bit integer.
Approach 1: Brute Force
Intuition
Check every possible contiguous subarray where . For each starting index i, continuously multiply elements as j expands from i to N - 1, tracking the maximum product observed so far.
Code Implementation
class Solution:
def maxProduct(self, nums: list[int]) -> int:
n = len(nums)
max_product = float('-inf')
for i in range(n):
current_product = 1
for j in range(i, n):
current_product *= nums[j]
max_product = max(max_product, current_product)
return max_productDry Run Example (nums = [2, 3, -2, 4])
| i | j | nums[j] | current_product | max_product |
|---|---|---|---|---|
| 0 | 0 | 2 | 2 | 2 |
| 0 | 1 | 3 | 6 | 6 |
| 0 | 2 | -2 | -12 | 6 |
| 0 | 3 | 4 | -48 | 6 |
| 1 | 1 | 3 | 3 | 6 |
| 1 | 2 | -2 | -6 | 6 |
| 1 | 3 | 4 | -24 | 6 |
| 2 | 2 | -2 | -2 | 6 |
| 2 | 3 | 4 | -8 | 6 |
| 3 | 3 | 4 | 4 | 6 |
Output: 6
Complexity Analysis
- Time Complexity: — Two nested loops iterating over all possible pairs of indices .
- Space Complexity: — Uses constant extra space for
max_productandcurrent_product.
Approach 2: Optimal Prefix and Suffix Products
Intuition & Key Insight
- No Negative / Even Negatives: If the array contains positive numbers and an even count of negative numbers, multiplying all elements yields the maximum product.
- Odd Negatives: If the array contains an odd number of negative numbers, dropping either the prefix up to the first negative number or the suffix after the last negative number leaves an even count of negative numbers. Hence, the maximum product subarray must be either a prefix product or a suffix product.
- Zeros: If the array contains
0, multiplying by0resets the product to0. A zero acts as a divider splitting the array into separate subarrays. Wheneverprefix_productorsuffix_productbecomes0, we reset it back to1on the next step.
Thus, traversing simultaneously from left-to-right (prefix_product) and right-to-left (suffix_product) guarantees capturing the maximum product subarray in a single pass.
Code Implementation
class Solution:
def maxProduct(self, nums: list[int]) -> int:
n = len(nums)
prefix_product = 1
suffix_product = 1
max_product = float('-inf')
for i in range(n):
if prefix_product == 0:
prefix_product = 1
if suffix_product == 0:
suffix_product = 1
prefix_product *= nums[i]
suffix_product *= nums[n - 1 - i]
max_product = max(max_product, prefix_product, suffix_product)
return max_productDry Run Example (nums = [2, 3, -2, 4])
| i | nums[i] (Prefix) | nums[n-1-i] (Suffix) | prefix_product | suffix_product | max_product |
|---|---|---|---|---|---|
| 0 | 2 | 4 | 2 | 4 | 4 |
| 1 | 3 | -2 | 6 | -8 | 6 |
| 2 | -2 | 3 | -12 | -24 | 6 |
| 3 | 4 | 2 | -48 | -48 | 6 |
Output: 6
Complexity Analysis
- Time Complexity: — Single pass through the array of length .
- Space Complexity: — Constant space used for tracking prefix, suffix, and max product.
Approach 3: Dynamic Programming / Modified Kadane’s Algorithm
Intuition
Unlike addition, multiplying by a negative number flips maximums into minimums and minimums into maximums. Therefore, at each step we track both:
cur_max: Max product ending at indexi.cur_min: Min (most negative) product ending at indexi.
When we encounter a negative number, multiplying swaps the roles of cur_max and cur_min.
Code Implementation
class Solution:
def maxProduct(self, nums: list[int]) -> int:
res = max(nums)
cur_min, cur_max = 1, 1
for n in nums:
if n == 0:
cur_min, cur_max = 1, 1
continue
tmp = cur_max * n
cur_max = max(n * cur_max, n * cur_min, n)
cur_min = min(tmp, n * cur_min, n)
res = max(res, cur_max)
return resComplexity Analysis
- Time Complexity: — One pass through the array.
- Space Complexity: — Scalar state tracking variables.
Edge Cases and Pitfalls
- Single Negative Element: e.g.,
nums = [-2].max_productcorrectly initialized tofloat('-inf')and updated to-2. - Zeros in Array: e.g.,
nums = [-2, 0, -1]. Zeros reset products to1, isolating zero-segmented subarrays. - Negative Numbers Count: Handled via prefix/suffix or dynamic min/max tracking.