Algorithm

Product of Array Except Self

Arrays & Strings Pattern

Product of Array Except Self

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.

CONSTRAINTS
  • 2 <= nums.length <= 10⁵
  • -30 <= nums[i] <= 30
  • The product of any prefix or suffix fits in a 32-bit integer
EXAMPLE 1
Input: nums = [1,2,3,4]
Output: [24,12,8,6]
For index 2 (value 3): left piece is 1 × 2 = 2, right piece is 4. Answer there: 2 × 4 = 8.
EXAMPLE 2
Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]
One zero: every index except the zero's own has 0 in its product. At the zero's index, the product of the others is (-1) × 1 × (-3) × 3 = 9.
EXAMPLE 3
Input: nums = [0,4,0]
Output: [0,0,0]
Two zeros: every index — even the zeros themselves — has at least one zero on some side, so everything is 0.
Why exactly is division not allowed?
Partly to force the intended technique, but the restriction is also principled: with a zero in the array the division approach computes 0 ÷ 0 at the zero's index, so it is genuinely broken, not merely forbidden.
Does the output array count towards the space limit?
By convention, no — the answer has to exist somewhere. 'O(1) extra space' means beyond the output. Worth stating this assumption to the interviewer explicitly.
Can the numbers be negative?
Yes. Signs simply multiply through the prefix and suffix products — no special handling is needed.

For every position i we must produce the product of all other elements. Read the problem statement again and notice something unusual: it hands you two explicit handcuffs — the solution must run in O(N), and division is banned. When a problem forbids the obvious tool by name, that prohibition is a signpost pointing at the technique it wants you to learn.

The honest brute force

For each of the N positions, multiply the other N - 1 numbers together — roughly N² multiplications, O(N²) time:

python
res = [1] * n
for i in range(n):
    for j in range(n):
        if i != j:
            res[i] *= nums[j]
return res
Why the division shortcut fails

The tempting fix: compute the total product of everything once, then answer[i] = total ÷ nums[i]. One pass, done? Apart from being explicitly forbidden, this genuinely breaks the moment a zero appears. With one zero in the array, the total product is 0, and at the zero's own index you would be computing 0 ÷ 0 — meaningless — even though the true answer there (the product of everyone else) may be perfectly nonzero. Division tries to undo a multiplication, and multiplication by zero destroys information that cannot be undone. So the ban is not arbitrary; we need an approach that never has to un-multiply anything.

The reframe: every answer is a left piece times a right piece

Excluding nums[i] splits the array cleanly in two: everything strictly to the left of i, and everything strictly to the right. So answer[i] = (product of the left piece) × (product of the right piece). That looks like more work — until you see how the left pieces relate to each other: the left product for position i+1 is just the left product for position i multiplied by nums[i]. One running value, swept left to right, produces all N left products in a single pass. The same sweep from the right end produces all right products. This precomputed running value is called a prefix product (and its mirror a suffix product) — the multiplicative cousin of a running total.

python
L, R = [1] * n, [1] * n            # L[i]: product of everything left of i
for i in range(1, n):              # R[i]: product of everything right of i
    L[i] = nums[i-1] * L[i-1]
for i in range(n-2, -1, -1):
    R[i] = nums[i+1] * R[i+1]

res = [L[i] * R[i] for i in range(n)]
return res

Two sweeps plus a combine: O(N) time, but two helper arrays of size N — O(N) extra space.

Folding the helpers into the output

The two helper arrays are never needed at the same time in full. Write the left products directly into the output array in pass 1; then walk backwards carrying the right-side product as a single running variable, multiplying it into each slot as you pass. (By convention — confirm it with the interviewer — the output array does not count as extra space, so this counts as O(1) space.)

python
res = [1] * n
left = 1
for i in range(n):        # pass 1: res[i] becomes product of everything left of i
    res[i] = left
    left *= nums[i]

right = 1
for i in range(n-1, -1, -1):   # pass 2: multiply in everything right of i
    res[i] *= right
    right *= nums[i]
Worked Example:nums = [1, 2, 3, 4]
- Pass 1 (left products): res = [1, 1, 2, 6]. Read it: nothing lies left of index 0 (empty product = 1); left of index 3 sits 1 × 2 × 3 = 6.
- Pass 2, i = 3: res[3] = 6 × 1 = 6, then right becomes 4.
- i = 2: res[2] = 2 × 4 = 8, right becomes 12.
- i = 1: res[1] = 1 × 12 = 12, right becomes 24.
- i = 0: res[0] = 1 × 24 = 24.
- Answer: [24, 12, 8, 6].
Zeros cost nothing here

Notice the approach never divides, so zeros need no special handling. One zero in the array: every other index has the zero inside its left or right piece, so every other answer is 0, while the zero's own index gets the honest product of everyone else. Two or more zeros: every index — including the zeros themselves — has some zero on one side, so the whole answer is zeros. The sweeps produce all of this automatically. The lesson worth keeping is the precomputation move itself: when each answer needs "everything to my left" and "everything to my right", two running sweeps assemble all N answers in linear time. Prefix sums and prefix products built this way underpin a large family of range problems you will meet later.

Interactive Strategy Visualization

Product Pre-Computation

Strategy: Dual Pass Accumulation
Input
1
2
3
4
5
Result
1
1
1
1
1
Starting Left Pass. Index 0: Nothing to the left, so store 1.
DIVISION-FREE

By calculating Left and Right products separately, we avoid dividing by zero—a common pitfall in this problem.

SPACE-SAVER

We reuse the output array for our prefix pass and update it on the suffix pass, achieving O(1) extra space.

O(N²) Brute Force
O(N)/O(N) Prefix+Suffix Arrays
O(N)/O(1) Two-Pass Fold