238. Product of Array Except Self - Explanation
Description
Given an integer array nums, return an array output where output[i] is the product of all the elements of nums except nums[i].
Each product is guaranteed to fit in a 32-bit integer.
Follow-up: Could you solve it in time without using the division operation?
Example 1:
Input: nums = [1,2,4,6]
Output: [48,24,12,8]Example 2:
Input: nums = [-1,0,1,2,3]
Output: [0,-6,0,0,0]Constraints:
2 <= nums.length <= 1000-20 <= nums[i] <= 20
Topics
Recommended Time & Space Complexity
You should aim for a solution as good or better than O(n) time and O(n) space, where n is the size of the input array.
Hint 1
A brute-force solution would be to iterate through the array with index i and compute the product of the array except for that index element. This would be an O(n^2) solution. Can you think of a better way?
Hint 2
Is there a way to avoid the repeated work? Maybe we can store the results of the repeated work in an array.
Hint 3
We can use the prefix and suffix technique. First, we iterate from left to right and store the prefix products for each index in a prefix array, excluding the current index's number. Then, we iterate from right to left and store the suffix products for each index in a suffix array, also excluding the current index's number. Can you figure out the solution from here?
Hint 4
We can use the stored prefix and suffix products to compute the result array by iterating through the array and simply multiplying the prefix and suffix products at each index.
Prerequisites
Before attempting this problem, you should be comfortable with:
- Prefix Sum/Product - Understanding how to build cumulative products from left-to-right and right-to-left to avoid recomputation
- Array Traversal - Making multiple passes through an array to build intermediate results efficiently
1. Brute Force
Intuition
For each position in the array, we can compute the product of all other elements by multiplying every value except the one at the current index.
This directly follows the problem statement and is the most straightforward approach:
for each index, multiply all elements except itself.
Although simple, this method is inefficient because it repeats a full pass through the array for every element.
Algorithm
- Let
nbe the length of the input array and create a result arrayresof sizen. - For each index
ifrom0ton - 1:- Initialize a running product
prod = 1. - Loop through all indices
jfrom0ton - 1:- If
jis not equal toi, multiplyprodbynums[j].
- If
- Store
prodinres[i].
- Initialize a running product
- After all indices are processed, return
res.
Time & Space Complexity
- Time complexity:
- Space complexity:
- extra space.
- space for the output array.
2. Division
Intuition
This approach works by using a simple idea:
If we know the product of all non-zero numbers, we can easily compute the answer for each position using division — as long as there are no division-by-zero issues.
So we first check how many zeros the array has:
- If there are two or more zeros, then every product will include at least one zero → the entire
resis all zeros. - If there is exactly one zero, then only the position containing that zero will get the product of all non-zero numbers. All other positions become
0. - If there are no zeros, we can safely do:
result[i] = total_product // nums[i]
Algorithm
- Traverse the array once:
- Multiply all non-zero numbers to get the
prod. - Count how many zeros appear.
- Multiply all non-zero numbers to get the
- If the
zero_cntis greater than1:- Return an array of all zeros.
- Create a result array of size
n. - Loop through the numbers again:
- If there is one zero:
- The index with zero gets the
prodof all non-zero numbers. - All other positions get
0.
- The index with zero gets the
- If there are no zeros:
- Set each result value to
prod // nums[i].
- Set each result value to
- If there is one zero:
- Return the result array.
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
prod, zero_cnt = 1, 0
for num in nums:
if num:
prod *= num
else:
zero_cnt += 1
if zero_cnt > 1: return [0] * len(nums)
res = [0] * len(nums)
for i, c in enumerate(nums):
if zero_cnt: res[i] = 0 if c else prod
else: res[i] = prod // c
return resTime & Space Complexity
- Time complexity:
- Space complexity:
- extra space.
- space for the output array.
3. Prefix & Suffix
Intuition
For each index, we need the product of all elements before it and all elements after it.
Instead of recomputing the product repeatedly, we can pre-compute two helpful arrays:
- Prefix product:
pref[i]= product of all elements to the left ofi - Suffix product:
suff[i]= product of all elements to the right ofi
Then, the final answer for each index is simply:
result[i] = pref[i] × suff[i]
This works because:
- The
prefhandles everything before the index - The
suffhandles everything after the index
Both pieces together form the product of all numbers except the one at that position.
Algorithm
Let
nbe the length of the array.
Create three arrays of sizen:preffor prefix productssufffor suffix productsresfor the final result
Set:
pref[0] = 1(nothing to the left of index0)suff[n - 1] = 1(nothing to the right of last index)
Build the prefix product array:
- For each
ifrom1ton - 1:pref[i] = nums[i - 1] × pref[i - 1]
- For each
Build the suffix product array:
- For each
ifromn - 2down to0:suff[i] = nums[i + 1] × suff[i + 1]
- For each
Build the result:
- For each index
i, compute:res[i] = pref[i] × suff[i]
- For each index
Return the result array.
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [0] * n
pref = [0] * n
suff = [0] * n
pref[0] = suff[n - 1] = 1
for i in range(1, n):
pref[i] = nums[i - 1] * pref[i - 1]
for i in range(n - 2, -1, -1):
suff[i] = nums[i + 1] * suff[i + 1]
for i in range(n):
res[i] = pref[i] * suff[i]
return resTime & Space Complexity
- Time complexity:
- Space complexity:
4. Prefix & Suffix (Optimal)
Intuition
We can compute the product of all elements except the current one without using extra prefix and suffix arrays.
Instead, we reuse the result array and build the answer in two simple passes:
- In the first pass, we fill
res[i]with the product of all elements to the left ofi(prefix product). - In the second pass, we multiply each
res[i]with the product of all elements to the right ofi(postfixproduct).
By maintaining two running values — prefix and postfix — we avoid the need for separate pref and suff arrays.
This gives us the same logic as the previous method, but with O(1) extra space.
Algorithm
- Initialize the result array
reswith all values set to1. - Create a variable
prefix = 1. - First pass (left to right):
- For each index
i:- Set
res[i] = prefix(product of all elements to the left). - Update
prefix *= nums[i].
- Set
- For each index
- Create a variable
postfix = 1. - Second pass (right to left):
- For each index
i:- Multiply
res[i]bypostfix(product of all elements to the right). - Update
postfix *= nums[i].
- Multiply
- For each index
- Return the result array
res.
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
res = [1] * (len(nums))
prefix = 1
for i in range(len(nums)):
res[i] = prefix
prefix *= nums[i]
postfix = 1
for i in range(len(nums) - 1, -1, -1):
res[i] *= postfix
postfix *= nums[i]
return resTime & Space Complexity
- Time complexity:
- Space complexity:
- extra space.
- space for the output array.
Common Pitfalls
Using Division Without Handling Zeros
The division approach (totalProduct / nums[i]) fails when the array contains zeros. Dividing by zero causes runtime errors, and having multiple zeros requires special handling. Always count zeros first: with two or more zeros, the entire result is zeros; with exactly one zero, only the zero's position gets the product of other elements.
Off-by-One Errors in Prefix/Suffix Array Construction
When building prefix products, pref[i] should contain the product of elements before index i, not including nums[i]. A common mistake is including nums[i] in the prefix, which double-counts the element. The same applies to suffix arrays: suff[i] should exclude nums[i].
Integer Overflow with Large Products
When the array contains many large numbers, the product can overflow 32-bit integers. In languages with fixed-size integers, consider using long or BigInteger. The problem constraints usually prevent overflow, but edge cases with many elements near the maximum value should be tested.
Sign in to join the discussion