LeetCode 238: Product of Array Except Self Solution Explained
Understanding the Problem
Given an integer array nums, return an array answer where answer[i] equals the product of all elements except nums[i]. The challenge? Solve without division in O(n) time with O(1) extra space (excluding output array). This constraint forces us beyond brute-force approaches.
Why Division Is Forbidden
The intuitive solution - multiply all elements then divide by nums[i] - fails because:
- Division by zero crashes when nums[i] = 0
- Problem explicitly prohibits division operations
- Real-world systems often restrict division due to higher computational cost
Brute-Force Approach (Not Optimal)
The initial nested loop solution:
- For each index i:
- Initialize product = 1
- For each index j:
- If i ≠ j: product *= nums[j]
- Store product in answer[i]
Time Complexity: O(n²) - Unacceptable for large inputs (n ≤ 10⁵)
Space Complexity: O(1) - But fails time constraints
Optimal Two-Pass Solution
Core Insight
answer[i] = (product of left elements) × (product of right elements)
- Left product: Prefix up to i-1
- Right product: Suffix from i+1
Step-by-Step Execution
Forward pass (Calculate left products):
- Initialize answer[0] = 1
- For i from 1 to n-1:
answer[i] = answer[i-1] × nums[i-1]
Backward pass (Incorporate right products):
- Initialize right_product = 1
- For i from n-1 down to 0:
*answer[i] = right_product
*right_product = nums[i]
Complexity Analysis
- Time: O(n) - Two linear passes
- Space: O(1) - Only variables (output array excluded)
Edge Case Handling
- Zero values: Naturally handled since multiplication propagates zeros
- Single element: Returns [1] since no other elements to multiply
Implementation Walkthrough
Consider nums = [1, 2, 3, 4]:
Forward Pass (Left products):
- i=0: answer[0] = 1 (no left elements)
- i=1: answer[1] = 1 × 1 = 1
- i=2: answer[2] = 1 × 2 = 2
- i=3: answer[3] = 2 × 3 = 6
Backward Pass (Apply right products):
- i=3: right_product=1 → answer[3]=6×1=6; Update right_product=1×4=4
- i=2: answer[2]=2×4=8; Update right_product=4×3=12
- i=1: answer[1]=1×12=12; Update right_product=12×2=24
- i=0: answer[0]=1×24=24
Result: [24, 12, 8, 6]
Key Optimization Insights
- Reuse output array: Store left products directly in answer
- Single variable for right products: Compute on-the-fly during reverse pass
- Avoid precomputation: Merge steps to eliminate extra arrays
Common Pitfalls to Avoid
- Modifying nums during processing: Always treat as read-only
- Ignoring space constraints: Using O(n) extra space fails optimization
- Incorrect initialization: right_product must start at 1
Advanced Follow-Ups
- Product with division allowed: How would solution change?
- Multi-dimensional arrays: Extend this approach to matrices
- Streaming data: Handle infinite input streams (sliding window variant)
Actionable Implementation Checklist
- Initialize answer array with size n
- Set answer[0] = 1
- Forward pass: Compute left products
- Set right_product = 1
- Backward pass: Multiply right products into answer
- Return answer
Practice Recommendation:
Reimplement this solution on LeetCode immediately - internalizing the two-pass pattern is critical for array manipulation problems.
"Which step in the backward pass do you anticipate being most challenging? Share your implementation hurdles below!"
Resources for Mastery:
- Book: "Elements of Programming Interviews" (Azetliyanos) - Chapter 5
- Tool: LeetCode Playground - Test edge cases interactively
- Community: r/leetcode - Discuss variants like "product of k nearest neighbors"