Maximum Product Subarray in DSA Rust - 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.
use std::cmp::{max, min};
fn max_product(nums: &[i32]) -> i32 {
let mut max_prod = nums[0];
let mut min_prod = nums[0];
let mut result = nums[0];
for &num in nums[1..].iter() {
let temp_max = max_prod;
max_prod = max(num, max(max_prod * num, min_prod * num));
min_prod = min(num, min(temp_max * num, min_prod * num));
result = max(result, max_prod);
}
result
}
This code finds the maximum product of any contiguous subarray in the input array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop that goes through each element of the array once.
- How many times: The loop runs (n - 1) times, where n is the number of elements in the array.
As the array size grows, the number of steps grows roughly the same way, one step per element after the first.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 9 |
| 100 | 99 |
| 1000 | 999 |
Pattern observation: The number of operations grows linearly with the input size.
Time Complexity: O(n)
This means the time to find the maximum product subarray grows in direct proportion to the size of the input array.
[X] Wrong: "Because we check multiple products inside the loop, the time complexity is more than linear, like O(n²)."
[OK] Correct: The multiple checks inside the loop are constant-time operations done once per element, so they do not multiply the loop count. The loop still runs only once per element, keeping the complexity linear.
Understanding this linear time solution shows you can handle problems that need careful tracking of multiple values while scanning an array once, a common skill in coding interviews.
"What if we used recursion instead of a loop to find the maximum product subarray? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem goal
The problem asks for a contiguous part of the array where the product of all numbers is as large as possible.Step 2: Differentiate from similar problems
This is different from sum problems or longest subarray problems; it focuses on product, not sum or length.Final Answer:
The contiguous subarray with the largest product of its elements -> Option DQuick Check:
Maximum product subarray = largest product contiguous segment [OK]
- Confusing product with sum
- Ignoring negative numbers impact
- Thinking about longest subarray instead
Solution
Step 1: Identify correct initialization
We must start with the first element of the array for max, min, and result to handle negative and positive values properly.Step 2: Check Rust syntax for mutable variables
Variables must be mutable (mut) to update during iteration, and tuple assignment is correct.Final Answer:
let (mut max_prod, mut min_prod, mut result) = (nums[0], nums[0], nums[0]); -> Option AQuick Check:
Initialize with first element and mut keyword [OK]
- Using zero instead of first element
- Not making variables mutable
- Using Option types unnecessarily
let nums = vec![2, 3, -2, 4];
let (mut max_prod, mut min_prod, mut result) = (nums[0], nums[0], nums[0]);
for &num in &nums[1..] {
if num < 0 {
let temp = max_prod;
max_prod = min_prod;
min_prod = temp;
}
max_prod = max_prod.max(num).max(max_prod * num);
min_prod = min_prod.min(num).min(min_prod * num);
result = result.max(max_prod);
}
println!("{}", result);Solution
Step 1: Trace iteration and variable updates
Start: max_prod=2, min_prod=2, result=2 - num=3: num>0, max_prod=max(2,3,2*3)=6, min_prod=min(2,3,2*3)=2, result=max(2,6)=6 - num=-2: num<0, swap max_prod and min_prod (max_prod=2, min_prod=6), max_prod=max(2,-2,2*-2)=2, min_prod=min(6,-2,6*-2)=-12, result=max(6,2)=6 - num=4: num>0, max_prod=max(2,4,2*4)=8, min_prod=min(-12,4,-12*4)=-48, result=max(6,8)=8Step 2: Check final result printed
The code prints the final result variable which is 8 after the last iteration.Final Answer:
8 -> Option BQuick Check:
Final max product = 8 [OK]
- Not swapping max and min on negative number
- Confusing max and min updates
- Forgetting to update result
let nums = vec![2, -5, -2, -4, 3];
let (mut max_prod, mut min_prod, mut result) = (nums[0], nums[0], nums[0]);
for &num in &nums[1..] {
if num > 0 {
let temp = max_prod;
max_prod = min_prod;
min_prod = temp;
}
max_prod = max_prod.max(num).max(max_prod * num);
min_prod = min_prod.min(num).min(min_prod * num);
result = result.max(max_prod);
}
println!("{}", result);Solution
Step 1: Analyze the swap condition
The code swaps max_prod and min_prod only if num > 0, but it should swap when num is negative to handle sign changes correctly.Step 2: Confirm other parts are correct
Variables are mutable, loop starts from index 1 correctly, and max/min methods are used properly.Final Answer:
The swap condition should be for negative numbers, not positive -> Option CQuick Check:
Swap on negative numbers only [OK]
- Swapping on positive numbers
- Not swapping at all
- Incorrect loop start index
nums = [-1, -3, -10, 0, 60], what is the maximum product subarray and its product?Solution
Step 1: Evaluate products of subarrays
Check subarrays: - [-1, -3, -10]: product = -1 * -3 * -10 = -30 - [60]: product = 60 - [-3, -10, 0]: product = 0 - Entire array: product = 0 The highest product is 60 from subarray [60].Step 2: Confirm no larger product exists
Other subarrays with zeros or negatives produce smaller or zero products.Final Answer:
Subarray: [60], Product: 60 -> Option AQuick Check:
Max product is 60 from single element [OK]
- Ignoring single positive elements after zero
- Multiplying negatives without sign check
- Assuming longer subarray always better
Ready to prove it?
Pass the test and this pattern moves unknown
