3.20 Product of Array Except Self
3.20.1 Problem Metadata
- Platform: LeetCode
- Problem ID: 238
- Difficulty: Medium
- URL: https://leetcode.com/problems/product-of-array-except-self/
- Tags: Grind 75, Blind 75, NeetCode 150
- Techniques: Array, Prefix Sum
3.20.2 Description
Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division operation.
3.20.3 Examples
Example 1:
Input: nums = [1,2,3,4]
Output: [24,12,8,6]
Explanation:
- answer[0] = 2 × 3 × 4 = 24
- answer[1] = 1 × 3 × 4 = 12
- answer[2] = 1 × 2 × 4 = 8
- answer[3] = 1 × 2 × 3 = 6
Example 2:
Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]
Explanation:
- answer[0] = 1 × 0 × (-3) × 3 = 0
- answer[1] = (-1) × 0 × (-3) × 3 = 0
- answer[2] = (-1) × 1 × (-3) × 3 = 9
- answer[3] = (-1) × 1 × 0 × 3 = 0
- answer[4] = (-1) × 1 × 0 × (-3) = 0
3.20.4 Constraints
- \(2 \le \text{nums.length} \le 10^5\)
- \(-30 \le \text{nums}[i] \le 30\)
- The product of any prefix or suffix of
numsis guaranteed to fit in a 32-bit integer
3.20.5 Follow-up
Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)
3.20.6 Solution - Prefix and Suffix Arrays
3.20.6.1 Walkthrough
This solution uses the prefix-suffix product pattern to compute the product of all elements except self without using division.
Core Strategy:
The key insight is that for any element at index i, the product of all other elements equals:
result[i] = (product of all elements before i) × (product of all elements after i)
We can precompute these products using two auxiliary arrays:
- Prefix array: prefix[i] stores the product of all elements before index i
- Suffix array: suffix[i] stores the product of all elements after index i
Step-by-step execution for nums = [1, 2, 3, 4]:
Build prefix array (left to right):
prefix[0] = 1 (no elements before index 0) prefix[1] = 1 (product of nums[0] = 1) prefix[2] = 1 × 2 = 2 (product of nums[0..1]) prefix[3] = 1 × 2 × 3 = 6 (product of nums[0..2]) → prefix = [1, 1, 2, 6]Build suffix array (right to left):
suffix[3] = 1 (no elements after index 3) suffix[2] = 4 (product of nums[3] = 4) suffix[1] = 3 × 4 = 12 (product of nums[2..3]) suffix[0] = 2 × 3 × 4 = 24 (product of nums[1..3]) → suffix = [24, 12, 4, 1]Compute result:
result[0] = prefix[0] × suffix[0] = 1 × 24 = 24 result[1] = prefix[1] × suffix[1] = 1 × 12 = 12 result[2] = prefix[2] × suffix[2] = 2 × 4 = 8 result[3] = prefix[3] × suffix[3] = 6 × 1 = 6 → result = [24, 12, 8, 6]
Why This Works:
For nums = [a, b, c, d] and index i = 1:
- prefix[1] contains product of elements before index 1: a
- suffix[1] contains product of elements after index 1: c × d
- result[1] = a × (c × d) which is the product except b ✓
This avoids division entirely while maintaining O(n) time complexity.
3.20.6.2 Analysis
- Time Complexity: O(n)
- First loop builds prefix array: O(n)
- Second loop builds suffix array: O(n)
- Third loop computes result: O(n)
- Total: O(n + n + n) = O(n)
- Space Complexity: O(n)
- Prefix array: O(n)
- Suffix array: O(n)
- Result array: O(n) (doesn’t count per problem statement)
- Total auxiliary space: O(n)
3.20.6.3 Implementation Steps
- Initialize three arrays of length
n:resultto store final outputprefixto store product of elements before each indexsuffixto store product of elements after each index
- Build prefix array (left to right):
- For index 0:
prefix[0] = 1(no elements before) - For indices 1 to n-1:
prefix[i] = prefix[i-1] × nums[i-1]
- For index 0:
- Build suffix array (right to left):
- For index n-1:
suffix[n-1] = 1(no elements after) - For indices n-2 down to 0:
suffix[i] = suffix[i+1] × nums[i+1]
- For index n-1:
- Compute result:
- For each index i:
result[i] = prefix[i] × suffix[i]
- For each index i:
- Return
result
3.20.6.4 Code - Java
class Solution {
public int[] productExceptSelf(int[] nums) {
int len = nums.length;
int[] result = new int[len];
//[1, 1, 1*2, 1*2*3]
int[] prefix = new int[len];
//[2*3*4, 3*4, 4, 1]
int[] suffix = new int[len];
for(int i = 0; i < len; i++) {
if(i == 0) {
prefix[i] = 1;
} else {
prefix[i] = prefix[i-1] * nums[i-1];
}
}
for(int i = len - 1; i >= 0; i--) {
if(i == len - 1) {
suffix[i] = 1;
} else {
suffix[i] = suffix[i+1] * nums[i+1];
}
}
for(int i = 0; i < len; i++) {
result[i] = prefix[i] * suffix[i];
}
return result;
}
}3.20.7 Solution - Space-Optimized (Follow-up)
3.20.7.1 Walkthrough
This solution achieves O(1) extra space by building the prefix and suffix products directly into the result array, eliminating the need for separate prefix/suffix arrays.
Core Strategy:
- First pass (left to right): Build prefix products in
resultarray - Second pass (right to left): Multiply by suffix products using a running variable
Step-by-step execution for nums = [1, 2, 3, 4]:
Pass 1 - Build prefix products:
i=0: result[0] = 1 (no elements before)
i=1: result[1] = 1 (product before: 1)
i=2: result[2] = 1 × 2 = 2 (product before: 1×2)
i=3: result[3] = 1 × 2 × 3 = 6 (product before: 1×2×3)
→ result = [1, 1, 2, 6]
Pass 2 - Multiply by suffix products:
suffix = 1 (start)
i=3: result[3] *= suffix → 6 × 1 = 6; suffix = 1 × 4 = 4
i=2: result[2] *= suffix → 2 × 4 = 8; suffix = 4 × 3 = 12
i=1: result[1] *= suffix → 1 × 12 = 12; suffix = 12 × 2 = 24
i=0: result[0] *= suffix → 1 × 24 = 24; suffix = 24 × 1 = 24
→ result = [24, 12, 8, 6]
Key Insight: The suffix variable accumulates the product of elements from right to left, eliminating the need for a separate suffix array.
3.20.7.2 Analysis
- Time Complexity: O(n)
- First pass: O(n)
- Second pass: O(n)
- Total: O(n)
- Space Complexity: O(1)
- Only uses one extra variable (
suffix) - Result array doesn’t count as extra space per problem statement
- This satisfies the follow-up requirement!
- Only uses one extra variable (
3.20.7.3 Implementation Steps
Initialize
resultarray of lengthnFirst pass (left to right) - Build prefix products:
result[0] = 1(no elements before index 0)- For i from 1 to n-1:
result[i] = result[i-1] × nums[i-1]
Second pass (right to left) - Multiply by suffix products:
- Initialize
suffix = 1(running product from right) - For i from n-1 down to 0:
- Multiply current result by suffix:
result[i] *= suffix - Update suffix:
suffix *= nums[i]
- Multiply current result by suffix:
- Initialize
Return
result
3.20.7.4 Code - Java
class Solution {
public int[] productExceptSelf(int[] nums) {
int len = nums.length;
int[] result = new int[len];
// First pass: build prefix products
result[0] = 1;
for(int i = 1; i < len; i++) {
result[i] = result[i-1] * nums[i-1];
}
// Second pass: multiply by suffix products
int suffix = 1;
for(int i = len - 1; i >= 0; i--) {
result[i] *= suffix;
suffix *= nums[i];
}
return result;
}
}