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.
- 2 <= nums.length <= 10⁵
- -30 <= nums[i] <= 30
- The product of any prefix or suffix fits in a 32-bit integer
nums = [1,2,3,4][24,12,8,6]nums = [-1,1,0,-3,3][0,0,9,0,0]nums = [0,4,0][0,0,0]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.
For each of the N positions, multiply the other N - 1 numbers together — roughly N² multiplications, O(N²) time:
res = [1] * n
for i in range(n):
for j in range(n):
if i != j:
res[i] *= nums[j]
return resThe 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.
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.
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 resTwo sweeps plus a combine: O(N) time, but two helper arrays of size N — O(N) extra space.
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.)
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]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.
Product Pre-Computation
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.