LeetCode #238 Medium

Product of Array Except Self

Build an array where position i holds the product of every value in nums except nums[i], without division.

Constraints
  • 2 <= nums.length <= 10⁵
  • -30 <= nums[i] <= 30
  • The input is generated such that answer[i] is guaranteed to fit in a 32-bit integer.
arrayprefix-productsuffix-product
Open on LeetCode ↗
02

Intuition

Product of array except self returns an array where each position holds the product of every other element. Two constraints shape the solution: division is forbidden, and the output array does not count toward the space complexity. The division ban is not arbitrary. Dividing the total product by each element breaks on zeros, and handling one zero, two zeros, and no zeros separately is exactly the messy case analysis the constraint exists to prevent. The clean approach splits each answer into two halves: - The product of everything except position i is the product of everything to its left times the product of everything to its right. So two passes suffice. The first walks left to right, writing into the output the running product of everything before each position. The second walks right to left, multiplying each entry by the running product of everything after it. The second pass needs only a single variable for the right-hand running product, not another array — which is how the solution reaches O(1) extra space. Both running products start at 1, not 0. Starting at zero makes every result zero, which is the most common bug here. The boundaries handle themselves: position 0 has nothing to its left, and its left product stays at the initial 1, which is correct since an empty product is 1. Zeros need no special handling at all. A single zero makes every other position zero automatically, and two zeros make everything zero — both fall out of the multiplication without a branch. The cost is O(n) time with O(1) extra space, excluding the output as the problem allows.

How to spot this pattern

When each output combines all elements except the current one, look for a left contribution and a right contribution. Prefix and suffix accumulation avoids rebuilding those two ranges for every index and avoids the problems division has with zero.

03

Approach

Try it first

Before reading on: price up what the direct approach costs here, then ask what you would need to remember from the left to avoid re-scanning. Aim for O(n) time and O(1) extra space.

1

Understand the division ban

Dividing the total product breaks on zeros, forcing separate cases for one zero, two zeros, and none. The constraint exists to rule out that mess.

2

Split into left and right

Each answer is the product of everything left of i times everything right of it. This decomposition is what makes two passes sufficient.

3

Sweep left to right

Write into the output the running product of all elements before each position. Position 0 receives the initial value, since nothing precedes it.

4

Start both products at one

Initialise the running products to 1, not 0. Starting at zero makes every result zero — the most common bug in this problem.

5

Sweep right to left

Multiply each output entry by the running product of everything after it, using a single variable rather than a second array.

6

Let zeros resolve themselves

No special handling is needed. One zero makes every other position zero automatically; two zeros make everything zero — both fall out of the multiplication.

7

Cost of the approach

Two linear passes give O(n) time and O(1) extra space, with the output array excluded as the problem permits.

04

Solution & live demo

▶1class Solution:
▶2 def productExceptSelf(self, nums:
▶3 List[int]) -> List[int]:
▶4 answer = [1] * len(nums)
▶5 prefix = 1
▶6 
▶7 for i in range(len(nums)):
▶8 answer[i] = prefix
▶9 prefix *= nums[i]
▶10 
▶11 suffix = 1
▶12 for i in range(len(nums) - 1, -1, -1):
▶13 answer[i] *= suffix
▶14 suffix *= nums[i]
▶15 
▶16 return answer
05

Common pitfalls

Using division despite zero values

✗ Wrong
answer[i] = total_product // nums[i]
✓ Right
answer[i] = prefix

Division is forbidden and becomes undefined at zero; separate side products work for every input.

Including the current number in the prefix

✗ Wrong
prefix *= nums[i]
answer[i] = prefix
✓ Right
answer[i] = prefix
prefix *= nums[i]

Updating first puts nums[i] into its own output, which violates the except-self requirement.

Updating the suffix before using it

✗ Wrong
suffix *= nums[i]
answer[i] *= suffix
✓ Right
answer[i] *= suffix
suffix *= nums[i]

The suffix must represent positions strictly to the right when it is multiplied into answer[i].

06

Edge cases

Exactly one zero, such as [1, 2, 0, 4]

The zero index combines non-zero prefix and suffix products, while every other position receives zero from one side.

Two or more zeros

Every index has a zero on its left or right, so both passes correctly produce all zeros.

Negative values

Prefix and suffix multiplication preserve signs without any special branch.

07

Complexity

Time
O(n)
Space
O(1) extra
The returned answer array is excluded from auxiliary space.