Given an integer array nums, find a subarray that has the largest product within the array and return it.
A subarray is a contiguous non-empty sequence of elements within an array.
You can assume the output will fit into a 32-bit integer.
Example 1:
Input: nums = [1,2,-3,4]
Output: 4Example 2:
Input: nums = [-2,-1]
Output: 2Constraints:
1 <= nums.length <= 1000-10 <= nums[i] <= 10
You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array.
A brute force solution would be to find the product for every subarray and then return the maximum among all the products. This would be an O(n ^ 2) approach. Can you think of a better way? Maybe you should think of a dynamic programming approach.
Try to identify a pattern by finding the maximum product for an array with two elements and determining what values are needed when increasing the array size to three. Perhaps you only need two values when introducing a new element.
We maintain both the minimum and maximum product values and update them when introducing a new element by considering three cases: starting a new subarray, multiplying with the previous max product, or multiplying with the previous min product. The max product is updated to the maximum of these three, while the min product is updated to the minimum. We also track a global max product for the result. This approach is known as Kadane's algorithm.
A subarray product can change drastically because of:
In brute force, we:
This works because every possible contiguous subarray is explicitly evaluated.
res with the first element.i:cur = nums[i].res.j > i:cur *= nums[j].res.res.The maximum-product subarray problem is tricky because:
So we can treat the array as separate segments split by zeros.
Inside one zero-free segment:
This “sliding window” idea maintains a window that contains an allowed number of negatives (even), shrinking from the left when we exceed that.
res as the maximum element seen so far (important for cases like all negatives or zeros).nums into zero-free subarrays (segments). Each zero ends a segment.need = negs).need = negs - 1).j..i with a running product:i to the right multiplying into prod.need, move j right, dividing out elements, until valid again.res with prod whenever the window is valid.res.class Solution:
def maxProduct(self, nums: List[int]) -> int:
A = []
cur = []
res = float('-inf')
for num in nums:
res = max(res, num)
if num == 0:
if cur:
A.append(cur)
cur = []
else:
cur.append(num)
if cur:
A.append(cur)
for sub in A:
negs = sum(1 for i in sub if i < 0)
prod = 1
need = negs if negs % 2 == 0 else negs - 1
negs = 0
j = 0
for i in range(len(sub)):
prod *= sub[i]
if sub[i] < 0:
negs += 1
while negs > need:
prod //= sub[j]
if sub[j] < 0:
negs -= 1
j += 1
if j <= i:
res = max(res, prod)
return resThis is the Kadane-style solution adapted for products.
In the classic maximum-sum subarray, we only track one value (current max sum).
For products, that’s not enough because:
So at every index, we must track two values:
curMax: maximum product ending at this index.curMin: minimum product ending at this index.Why curMin matters:
curMin might produce a new maximum.Zeros are naturally handled because choosing num alone can reset the product.
res = first element (answer so far).curMax = 1, curMin = 1.num in the array:curMax * num (because curMax will be updated).curMax as the maximum of:num (start new subarray).num * curMax (extend previous max).num * curMin (negative flip case).curMin as the minimum of:num.curMax * num.num * curMin.res = max(res, curMax).res.The key idea is that the maximum product subarray must appear as either:
Why this works:
By scanning:
we implicitly consider all valid subarrays without explicitly tracking negatives.
The (prefix or 1) trick resets the product after encountering 0.
res as the first element.prefix = 0, suffix = 0.i from 0 to n - 1:prefix = nums[i] * (prefix if prefix != 0 else 1).suffix = nums[n - 1 - i] * (suffix if suffix != 0 else 1).res = max(res, prefix, suffix).res.Unlike maximum sum subarray, a very negative product can become the maximum after multiplying by another negative number. Tracking only the current maximum is insufficient. You must track both curMax and curMin because multiplying curMin by a negative number might produce the new maximum.
A zero in the array resets the product to zero and effectively splits the array. After encountering a zero, the subarray must restart fresh. Failing to handle this case causes the algorithm to carry forward zero products incorrectly.
When computing the new curMax and curMin, the calculation for curMin may depend on the old value of curMax. Updating curMax first and then using the new value to compute curMin produces wrong results. Always store curMax * num in a temporary variable before updating either value.