Maximum Product Subarray
Walk left to right and keep two values: curMax, the biggest product of a block that ends at the current index, and curMin, the smallest. A block ending here is either the new number alone or an earlier block times the new number, so the biggest comes from x, x · curMax, or x · curMin. We keep the smallest too, because a negative x turns the smallest product into the biggest.
The two extremes are enough: the biggest and smallest products ending at i − 1 decide the biggest and smallest products ending at i.
Problem
You are given an integer array nums. Look at every contiguous block: a run of numbers that sit next to each other with nothing skipped. The product of a block is all its numbers multiplied together.
Return the largest product that any non-empty block has.
An integer array nums of length n.
A single integer: the largest product of any non-empty contiguous block.
The block [2, 3] gives 6. Adding the -2 makes the product negative: the whole array gives -48, so 6 is the best.
Any block that contains the 0 has product 0. The single blocks [-2] and [-1] are negative, so the best is 0.
- • 1 ≤ nums.length ≤ 2 × 10^4
- • −10 ≤ nums[i] ≤ 10
- • The product of any contiguous block fits in a 32-bit integer.
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
For the maximum sum of a block, I kept only the best sum that ends here. Why might that break when I multiply instead of add?
- 2.
If the best product ending at the previous index is very negative, what happens after I multiply it by another negative number?
- 3.
What does a 0 do to every block that contains it?
- 4.
How many blocks end at index i, and can I reuse what I already found for index i − 1?
- 5.
Is there any other block ending at i − 1 that could still matter after the next multiply?
Brute force approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Multiply each start's numbers one by one; track the largest product | O(N^2) | O(1) |
| Optimal | Keep the largest and smallest product of blocks ending here; a negative number swaps their roles | O(N) | O(1) |
Why does this belong to this pattern?
- “contiguous block”The answer is a range [l … r], so we walk left to right and keep a running state that ends at each index.
- “largest product”Multiplying a longer block does not always help, so one running value is not enough.
- “numbers can be negative”A negative number flips the sign, so the smallest product can become the largest. We must track both.
This is Kadane's idea with a second state. Plain Kadane keeps only the best sum ending here, which is safe for sums because adding never reverses the order. Multiplying by a negative number does reverse it, so the smallest product must be kept as well. The next question, Maximum Length with Positive Product, walks the same way but keeps lengths instead of product values.
Don't make this mistake
On the dry run [2, 3, -2, -4, 0, -1, 5] the largest-only version keeps 6 after the 3. Then -2 replaces it with -2, which throws away the -12. At -4 it gets max(-4, -4 · -2) = 8, and the program returns 8. The true answer is 48, from 2 · 3 · (-2) · (-4), and it needs the -12.
On the same dry run, after -2 the new curMax is -2. Then curMin = min(-2, -2 · -2, -2 · 3) = -6 instead of -12. At -4 the code returns max(-4, 8, 24) = 24, not 48. Both values must come from the old state.
With curMax = 0, a negative first number gives max(x, 0) = 0. For nums = [-3] the program returns 0 instead of -3, because the answer must be a real block.
A block can start fresh at x. For nums = [0, 2], both values are 0 after the zero, so without x alone the 2 is never considered and the program returns 0 instead of 2.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like DP — Kadane / Subarray translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.