Maximum Product Subarray in DSA Go - Time & Space Complexity
We want to understand how the time needed to find the maximum product of a subarray changes as the input array grows.
How does the number of steps grow when the array gets bigger?
Analyze the time complexity of the following code snippet.
func maxProduct(nums []int) int {
maxProd, minProd, result := nums[0], nums[0], nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] < 0 {
maxProd, minProd = minProd, maxProd
}
maxProd = max(nums[i], maxProd*nums[i])
minProd = min(nums[i], minProd*nums[i])
if maxProd > result {
result = maxProd
}
}
return result
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
This code finds the maximum product of any contiguous subarray in the input array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Single loop traversing the array once.
- How many times: Exactly once for each element after the first.
As the array size grows, the number of steps grows directly with it.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The steps increase in a straight line as input size increases.
Time Complexity: O(n)
This means the time to find the maximum product grows linearly with the size of the input array.
[X] Wrong: "Because we check products of subarrays, the time must be quadratic O(n²)."
[OK] Correct: The code cleverly keeps track of max and min products as it goes, so it only needs one pass through the array, not checking all subarrays separately.
Understanding this linear time approach shows you can optimize problems that seem to require checking many combinations, a valuable skill in interviews and real projects.
"What if we used a nested loop to check every subarray product instead? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem statement
The problem asks for a contiguous part of the array where the product of all elements is the highest possible.Step 2: Differentiate from similar problems
Unlike maximum sum subarray, here we multiply elements, so negative numbers and zeros affect the product differently.Final Answer:
The contiguous subarray with the largest product of its elements -> Option DQuick Check:
Maximum product subarray = contiguous subarray with max product [OK]
- Confusing product with sum
- Ignoring negative numbers impact
- Thinking about non-contiguous elements
Solution
Step 1: Understand initialization for max product subarray
We start with the first element as initial max, min, and result to handle negative and positive values correctly.Step 2: Check each option's initialization
maxProd, minProd, result := nums[0], nums[0], nums[0] uses nums[0] which is correct; others use fixed values that may not match array's first element.Final Answer:
maxProd, minProd, result := nums[0], nums[0], nums[0] -> Option CQuick Check:
Initialize with first element for correct tracking [OK]
- Initializing with zero causes wrong results if nums[0] is negative
- Using 1 ignores negative or zero first elements
- Not initializing minProd separately
nums := []int{2, 3, -2, 4}?
func maxProduct(nums []int) int {
maxProd, minProd, result := nums[0], nums[0], nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] < 0 {
maxProd, minProd = minProd, maxProd
}
maxProd = max(nums[i], maxProd*nums[i])
minProd = min(nums[i], minProd*nums[i])
if maxProd > result {
result = maxProd
}
}
return result
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}Solution
Step 1: Trace the loop and update maxProd, minProd, and result
Start with maxProd=2, minProd=2, result=2 - i=1 (3): nums[i]=3 > 0, maxProd=max(3,2*3)=6, minProd=min(3,2*3)=3, result=6 - i=2 (-2): nums[i]<0, swap maxProd and minProd (maxProd=3, minProd=6), maxProd=max(-2,3*(-2))=-2, minProd=min(-2,6*(-2))=-12, result=6 - i=3 (4): nums[i]>0, maxProd=max(4,-2*4)=4, minProd=min(4,-12*4)=-48, result=6Step 2: Determine final result
The maximum product found is 6 from subarray [2,3].Final Answer:
6 -> Option AQuick Check:
Max product subarray = 6 [OK]
- Not swapping max and min on negative number
- Confusing max and min updates
- Ignoring update of result
func maxProduct(nums []int) int {
maxProd, minProd, result := nums[0], nums[0], nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] > 0 {
maxProd = max(maxProd*nums[i], nums[i])
minProd = min(minProd*nums[i], nums[i])
} else {
maxProd = max(minProd*nums[i], nums[i])
minProd = min(maxProd*nums[i], nums[i])
}
if maxProd > result {
result = maxProd
}
}
return result
}Solution
Step 1: Analyze handling of negative numbers
When nums[i] is negative, maxProd and minProd should be swapped before updating because multiplying by negative flips max and min.Step 2: Check the code's else block
The code updates maxProd and minProd without swapping, causing incorrect results for negative numbers.Final Answer:
Swapping maxProd and minProd is missing when nums[i] is negative -> Option AQuick Check:
Swap max and min on negative input [OK]
- Forgetting to swap maxProd and minProd
- Updating maxProd before minProd causing wrong minProd
- Starting loop at wrong index
nums := []int{-1, -3, -10, 0, 60}, what is the maximum product subarray and its product?Solution
Step 1: Evaluate products of possible subarrays
Check subarrays: - [-1, -3, -10]: product = -1 * -3 * -10 = -30 - [60]: product = 60 - [-3, -10, 0, 60]: product = 0 (due to zero) - [-10, 0, 60]: product = 0 (due to zero)Step 2: Identify maximum product
The highest product is 60 from subarray [60].Final Answer:
Subarray [60] with product 60 -> Option BQuick Check:
Max product = 60 from single element [OK]
- Multiplying negative numbers without counting sign flips
- Ignoring zero resets product
- Assuming longer subarray always has max product
Ready to prove it?
Pass the test and this pattern moves unknown
