Lessons

Arrays

Dynamic Programming

Graph

Hashing

Maximum Product Subarray

The Maximum Product Subarray problem challenges you to find the contiguous subarray within an array that has the highest possible product. Unlike the maximum subarray sum, the introduction of negative numbers, positive numbers, and zero significantly affects the result, making it more complex and interesting.

Solving this efficiently requires a careful optimization strategy combined with dynamic programming principles. Let's dive into the methods, ideas, and Python implementation.

Problem Statement

Given an integer array, find the contiguous subarray that produces the maximum product.

Example:
Input: [2,3,-2,4]
Output: 6
Explanation: The subarray [2,3] has the product 6, which is the maximum among all subarrays.

Because of the presence of negative numbers and zero, we must rethink how to design the solution beyond simple multiplication.

Why a Simple Approach Fails

If we simply multiply elements as we do in the sum version, encountering a zero or a negative number can reset or flip the result entirely.

Thus, a simple iteration without smart tracking would miss correct answers, especially when a later negative number could flip a minimum into a maximum.

Optimized Approach Using Dynamic Programming

The right optimization strategy involves maintaining both a local maximum and a local minimum at every step:

  • A local maximum keeps track of the highest product ending at the current element.
  • A local minimum keeps track of the lowest product ending at the current element, because multiplying two negative numbers could yield a new positive number.

During the iteration, each new element can:

  • Increase the existing local maximum.
  • Turn the local minimum into a new local maximum (when multiplying two negatives).
  • Reset everything if the element is zero.

This clever tracking makes sure that no potential maximum is missed.

Step-by-Step Algorithm

  1. Initialize local_max, local_min, and global_max to the first element of the array.
  2. For each element from the second position onward:
    • If the element is negative, swap local_max and local_min.
    • Update local_max as the maximum between the current element and local_max * current element.
    • Update local_min similarly.
    • Update global_max if local_max exceeds it.

This method guarantees a complete dynamic programming solution with proper optimization.

Python Implementation

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def maxProduct(nums):
    if not nums:
        return 0
    
    local_max = nums[0]
    local_min = nums[0]
    global_max = nums[0]
    
    for num in nums[1:]:
        if num < 0:
            local_max, local_min = local_min, local_max
        
        local_max = max(num, local_max * num)
        local_min = min(num, local_min * num)
        
        global_max = max(global_max, local_max)
    
    return global_max

This code performs a linear iteration over the array, ensuring O(n) time complexity and O(1) space complexity.

Handling Special Cases

  • If the array contains a zero, the product must reset because anything multiplied by zero becomes zero.
  • Multiple negative numbers can cancel each other out to produce a new positive number.
  • A subarray containing a single element may still be the correct answer if it's the maximum.

Correct tracking during iteration ensures that all these cases are automatically handled.

Conclusion

The Maximum Product Subarray is a fascinating blend of careful array processing, smart subarray product tracking, and effective use of dynamic programming.
By maintaining a local maximum and local minimum and resetting around zero, we achieve perfect optimization for both time and space.

Mastering this pattern not only helps in solving similar problems involving negative numbers and positive numbers but also strengthens your skills in iteration-based algorithms.

Frequently Asked Questions