Definition
- Maximum product subarray asks for the largest product of any contiguous non-empty subarray.
- A negative element can turn the smallest product into the largest, so track both max and min.
- At each position, consider three candidates:
nums[i],prevMax * nums[i],prevMin * nums[i]. - A zero resets both products, and the next element restarts the subarray.
- Compute both new values from the previous values before overwriting.
- Time is O(N) and space is O(1).
At the National Bank of India, Rajesh reviews a sequence of daily portfolio growth multipliers: 1.1 means a ten percent gain, 0.9 means a ten percent loss, and a negative multiplier models a reversed position. He wants the most profitable continuous stretch when daily multipliers are chained together. Because two bad days can multiply into a great result, he must remember both his best and worst running products each day.
Understanding the Concepts
What is the Maximum Product Subarray problem?
Given an array of integers that may include negative numbers and zeros, find the maximum product obtainable from any contiguous non-empty subarray. This is LeetCode 152.
For example, given [2, 3, -2, 4], the maximum product is 6 from the subarray [2, 3].
Why do we need both max and min products?
Unlike sums, products have a twist: multiplying by a negative number flips the sign. The largest product so far becomes the smallest, and the smallest becomes the largest. Keeping only a running maximum is not enough because the real champion might be hiding in a very negative running minimum that a later negative flips into a large positive.
// Example: [-2, 3, -4]
// After -2: max=-2, min=-2
// After 3: max=3, min=-6 (3 alone is better than -2*3=-6)
// After -4: max=24, min=-12 (min*(-4)=(-6)*(-4)=24!)
// The answer 24 came from the MIN track, not the MAX track
How does the algorithm work?
package com.bank.service;
public class MaxProductSubarrayService {
/**
* Finds the most profitable continuous multiplier chain.
* Used by the National Bank of India wealth-management desk.
*/
public static long maxProduct(int[] multipliers) {
long prevMax = multipliers[0];
long prevMin = multipliers[0];
long globalMax = multipliers[0];
for (int i = 1; i < multipliers.length; i++) {
long val = multipliers[i];
// Compute from previous values before overwriting
long candMax = Math.max(val,
Math.max(prevMax * val, prevMin * val));
long candMin = Math.min(val,
Math.min(prevMax * val, prevMin * val));
prevMax = candMax;
prevMin = candMin;
globalMax = Math.max(globalMax, prevMax);
}
return globalMax;
}
public static void main(String[] args) {
int[] multipliers = {2, 3, -2, 4, -1};
System.out.println("Max product: " + maxProduct(multipliers));
}
}
javac -d out com/bank/service/MaxProductSubarrayService.java
java -cp out com.bank.service.MaxProductSubarrayService
Max product: 48
How does the swap trick simplify the code?
A cleaner way to handle the negative flip is to swap the running maximum and minimum whenever the current element is negative, then update each normally.
for (int i = 1; i < nums.length; i++) {
if (nums[i] < 0) {
long temp = prevMax;
prevMax = prevMin;
prevMin = temp;
}
prevMax = Math.max(nums[i], prevMax * nums[i]);
prevMin = Math.min(nums[i], prevMin * nums[i]);
globalMax = Math.max(globalMax, prevMax);
}
How are zeros handled?
Multiplying by zero collapses both running products to zero. The next element simply restarts the subarray from itself, because Math.max(next, 0 * next) = Math.max(next, 0) = next (for positive next). Zeros are natural terminators that split the array into segments.
// Example: [2, 3, 0, 4, 5]
// After 0: max=0, min=0 (both reset)
// After 4: max=4, min=4 (restart)
// After 5: max=20, min=20
What are the edge cases?
Several edge cases require attention.
- Single negative element: the answer is that negative number.
- Two negatives: their product is positive and may be the answer.
- All zeros: the answer is 0.
- Odd count of negatives: the maximum product excludes one negative from either end.
- Overflow: products grow much faster than sums. Use
longand test with large inputs.
package com.bank.core;
public class MaxProductEdgeCases {
public static void main(String[] args) {
System.out.println(maxProd(new int[]{-5})); // -5
System.out.println(maxProd(new int[]{-3, -4})); // 12
System.out.println(maxProd(new int[]{0, 0, 0})); // 0
System.out.println(maxProd(new int[]{-1, -2, -3})); // 6
}
static long maxProd(int[] arr) {
long pMax = arr[0], pMin = arr[0], best = arr[0];
for (int i = 1; i < arr.length; i++) {
long a = pMax * arr[i], b = pMin * arr[i];
pMax = Math.max(arr[i], Math.max(a, b));
pMin = Math.min(arr[i], Math.min(a, b));
best = Math.max(best, pMax);
}
return best;
}
}
-5
12
0
6
What is the time and space complexity?
Time is O(N): a single pass with constant work per element. Space is O(1): three scalar variables. This is optimal.
How is this different from maximum subarray sum?
The key difference is that products require tracking both max and min, while sums only need the max.
| Aspect | Max Subarray Sum | Max Product Subarray |
|---|---|---|
| State variables | 1 (currentMax) | 2 (currentMax, currentMin) |
| Why? | Sums do not flip sign | Products flip on negatives |
| Zero handling | Natural (adds zero) | Resets products |
| Overflow risk | Moderate | High (products grow fast) |
What should a senior engineer know?
A senior engineer should understand these deeper aspects.
- Dual tracking is the one key idea: the entire difference from sum Kadane is carrying two running values instead of one.
- Snapshot before overwrite: computing both new max and min from the previous values before overwriting is the implementation pitfall.
- Test three cases: odd negatives, paired negatives, and embedded zeros are the three cases where naive solutions break.
- Prefix-suffix product approach: an alternative O(N) approach computes prefix products left to right and suffix products right to left, taking the maximum across both, which avoids tracking min entirely.
Visual Overview
Multipliers: [2, 3, -2, 4, -1] ┌──────────────────────────────────────────────┐ │ i=0: pMax=2, pMin=2, best=2 │ │ i=1: pMax=6, pMin=3, best=6 │ │ i=2: pMax=-2, pMin=-12, best=6 │ │ (negative flipped: -2 > 6*-2=-12) │ │ i=3: pMax=4, pMin=-48, best=6 │ │ (restart at 4 > -2*4=-8) │ │ i=4: pMax=48, pMin=-4, best=48 │ │ (min*(-1)=(-48)*(-1)=48!) │ └──────────────────────────────────────────────┘ Answer: 48 (the min track delivered the winner) Why dual tracking: ┌──────────────────────┐ │ Negative × Negative │ │ = Positive │ │ │ │ The minimum product │ │ can become the max │ │ after one negative │ └──────────────────────┘
Key Takeaway
The maximum product subarray problem asks for the largest product of any contiguous non-empty subarray in an array that can include negatives and zeros. The crucial difference from the sum version is that products flip under multiplication by a negative, so the smallest running product can suddenly become the largest. You carry two running values: the maximum product and the minimum product ending at each position.
At each element, you consider the element alone, the element times the previous max, and the element times the previous min, taking the largest as the new max and the smallest as the new min. You compute both from the previous values before overwriting either. Zeros collapse both products and the next element restarts the subarray.
At the National Bank of India, Rajesh used this on the wealth-management desk. Daily growth multipliers for client portfolios included gains, losses, and reversed positions (negatives). The team needed the most profitable continuous stretch when multipliers compounded. Because negative multipliers could flip a losing streak into a winning one, the dual max-and-min tracking was essential.
The senior-level insight is that tracking both max and min is the one idea that separates the product problem from the sum problem. Being able to explain why a negative forces dual state, and testing against odd negatives, paired negatives, and embedded zeros, shows genuine understanding.
Remember one sentence: track both running max and min products because a negative flips their roles, and the maximum product may emerge from the minimum track.
---