Product of Array Except Self
Product of Array Except Self: Prefix and Suffix Patterns
Welcome back to codinginterview.net. If you have been following our curriculum, you are getting comfortable with array transformations, frequency maps, and mathematical tricks. Today, we are tackling a classic top-tier interview question: Product of Array Except Self. This problem tests your ability to break complex array dependency problems into independent prefix and suffix passes, all while enforcing a strict constraint: no division allowed. By the end of this guide, constructing optimal O(N) time and O(1) extra space solutions using running products will be second nature to you.
1. Understanding the Problem
You are given an integer array nums. Your task is to return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
For example, if nums = [1, 2, 3, 4], the output array will be [24, 12, 8, 6].
The Core Constraints (The Traps):
This problem comes with two strict constraints that force you away from simple shortcuts:
- You must write an algorithm that runs in O(N) time.
- You cannot use the division operation.
- Follow-up challenge: Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis).
2. The Forbidden Naive Approach: Total Product with Division
If division were allowed, the problem would be trivial: multiply all numbers in the array to get a total product, then loop through the array and calculate answer[i] = total_product / nums[i].
Why This Fails
- Violation of Rules: The problem explicitly forbids division.
- Division by Zero Edge Cases: If the array contains a
0, calculatingtotal_product / 0raises an undefined division error. If it contains multiple zeros, every output element becomes zero.
3. The Optimal Approach: Prefix and Suffix Products (O(1) Extra Space)
Notice that for any element at index i, the product of all elements except nums[i] can be decomposed into two separate parts:
answer[i] = (product of all numbers to the left of i) × (product of all numbers to the right of i)
Instead of re-calculating products for every index—which would take O(N²) time—we can perform two linear scans:
- First Pass (Left to Right): Fill the output array with the running product of all elements to the left of each index.
- Second Pass (Right to Left): Multiply the values in the output array by a running product of all elements to the right of each index.
By using our final output array to store the prefix products directly, we eliminate the need for separate array allocations, achieving optimal O(1) extra space!
4. The Logic Step-by-Step
- Initialize an array
answerof sizenwhere every element is set to 1. - Initialize a variable
prefix = 1. - Left Pass: Iterate through the array from left to right (
i = 0ton - 1):- Set
answer[i] = prefix(the product of all elements before indexi). - Update
prefix = prefix * nums[i].
- Set
- Initialize a variable
suffix = 1. - Right Pass: Iterate through the array backwards from right to left (
i = n - 1down to0):- Multiply
answer[i]bysuffix(answer[i] *= suffix). - Update
suffix = suffix * nums[i].
- Multiply
- Return
answer.
5. Complexity Analysis
- Time Complexity: O(N) — We scan the array twice (once left-to-right, once right-to-left). Processing each element takes O(1) arithmetic operations.
- Space Complexity: O(1) Extra Space — Beyond two scalar variables (
prefixandsuffix), we allocate zero additional memory. The output array is explicitly excluded from space complexity evaluation.
6. Code Implementations
Expand the sections below to see the optimal O(1) extra space implementations across different languages.
View Python Solution
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
answer = [1] * n
# Step 1: Calculate left (prefix) products
prefix = 1
for i in range(n):
answer[i] = prefix
prefix *= nums[i]
# Step 2: Calculate right (suffix) products on the fly
suffix = 1
for i in range(n - 1, -1, -1):
answer[i] *= suffix
suffix *= nums[i]
return answer
View Java Solution
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] answer = new int[n];
// Step 1: Calculate left (prefix) products
int prefix = 1;
for (int i = 0; i < n; i++) {
answer[i] = prefix;
prefix *= nums[i];
}
// Step 2: Calculate right (suffix) products on the fly
int suffix = 1;
for (int i = n - 1; i >= 0; i--) {
answer[i] *= suffix;
suffix *= nums[i];
}
return answer;
}
}
View C++ Solution
#include <vector>
class Solution {
public:
std::vector<int> productExceptSelf(std::vector<int>& nums) {
int n = nums.size();
std::vector<int> answer(n, 1);
// Step 1: Calculate left (prefix) products
int prefix = 1;
for (int i = 0; i < n; ++i) {
answer[i] = prefix;
prefix *= nums[i];
}
// Step 2: Calculate right (suffix) products on the fly
int suffix = 1;
for (int i = n - 1; i >= 0; --i) {
answer[i] *= suffix;
suffix *= nums[i];
}
return answer;
}
};
7. Conclusion: You Are Ready
Congratulations! You have successfully mastered the Prefix and Suffix technique for Product of Array Except Self! By splitting global dependencies into two unidirectional scans, you bypassed the strict "no division" rule while achieving optimal O(N) time and O(1) extra space. This two-pass prefix/suffix strategy is a foundational mental model that appears frequently in advanced sliding window, subarray, and dynamic programming interview challenges. Keep practicing, and keep optimizing!