Skip to content
QSWEQB
mediumCodingEntryMidSenior

For every index, give me the product of all the other elements - and you cannot use division.

Two passes over the array do it: a left-to-right pass writes the product of everything before each index into the output, then a right-to-left pass multiplies in a running product of everything after it. Linear time, no working array beyond the output, and it is unbothered by zeros.

3 min readUpdated 2026-07-26Asked at Amazon, Microsoft, Facebook

What the interviewer is scoring

  • Does the candidate decompose each answer into a before-part and an after-part rather than reaching for nested loops
  • Whether zeros are raised unprompted, since they are what kills the division shortcut
  • That the output array is explicitly counted or excluded when the space bound is stated, instead of an unqualified O(1) claim
  • Whether the second pass reuses the output array rather than allocating a third one
  • Does the candidate ask about value ranges before assuming the products fit in an int

Answer

Decomposing the answer

The answer at index i is the product of everything to the left of i multiplied by the product of everything to the right of i. That sentence is the entire solution, and saying it before writing code is most of what is being graded, because it converts an all-pairs-looking problem into two independent linear scans.

Nested loops give O(n²) and every candidate sees them. The division trick - compute the total product once, then divide by nums[i] - is O(n) and looks clever, but it is wrong the moment any element is zero, and interviewers who forbid division are usually forbidding it because they want the decomposition rather than the arithmetic.

The two passes

The output array itself carries the left-hand products after the first pass, so no separate prefix array is needed. The second pass walks backwards holding one scalar, the running product of everything seen so far from the right, and multiplies it into each cell before folding that cell's own value into the scalar.

int[] productExceptSelf(int[] nums) {
    int n = nums.length;
    int[] out = new int[n];

    out[0] = 1;                              // nothing to the left of index 0
    for (int i = 1; i < n; i++) {
        out[i] = out[i - 1] * nums[i - 1];   // note nums[i - 1], not nums[i]
    }

    int suffix = 1;
    for (int i = n - 1; i >= 0; i--) {
        out[i] *= suffix;                    // multiply in before updating, so nums[i] is excluded
        suffix *= nums[i];
    }
    return out;
}

Two lines decide whether this compiles into a correct answer. The first pass reads nums[i - 1] because out[i] must exclude nums[i]; reading nums[i] there is the single most common bug and it silently produces the product of everything up to and including i. In the second pass the multiplication happens before suffix absorbs nums[i], for the same reason in mirror image.

Time is O(n) with two passes and a constant number of multiplications each. Correctness for a length-1 array falls out: the first loop does not execute, the second sets out[0] = 1, which is the empty product.

The space claim is where answers get lost

Candidates say "O(1) extra space" and stop. That claim needs a qualifier, and an interviewer who has heard it a hundred times will push on it. The output array is O(n), and it is only excusable to exclude it because the problem requires you to return it - it is the result, not workspace. Say that out loud: "O(1) auxiliary space excluding the output, which is required by the signature." A candidate who instead allocates separate left[] and right[] arrays and calls it O(1) has not understood the bound they are quoting.

The other unqualified claim is arithmetic. The product of a long array of modest integers overflows 32 bits fast, and the correct move is to ask what the constraints guarantee rather than to reach for long reflexively or ignore it entirely.

Generalising the shape

What the technique needs is an associative operation with an identity element, so that a range can be split at any point and the two halves combined. Multiplication with identity 1 and addition with identity 0 both qualify, which is why this problem and range-sum queries are the same technique wearing different clothes.

For sums, the usual formulation keeps an explicit prefix array with a sentinel at the front, and that sentinel is worth the extra slot because it removes the special case at l == 0:

long[] prefix = new long[n + 1];                   // prefix[0] = 0 is the empty-prefix sentinel
for (int i = 0; i < n; i++) {
    prefix[i + 1] = prefix[i] + nums[i];
}
long rangeSum = prefix[r + 1] - prefix[l];         // nums[l..r] inclusive, no branch needed

Subtraction is what makes the sum version support arbitrary ranges in O(1), and that is precisely what products lose: dividing to undo a multiplication is not available when an element may be zero. So the two-pass form is not merely an alternative to a prefix-product array, it is the form that survives the operation not having an inverse. Recognising that is the difference between having memorised one problem and owning the pattern.

Likely follow-ups

  • If division were allowed, how would you handle exactly one zero, and then two zeros?
  • This works for multiplication and addition. What property of the operation does the technique need?
  • How would you serve thousands of range-product queries over a static array?
  • Can you do the same thing in one pass if you are allowed to write into the output twice?

Related questions

prefix-sumarraystwo-passin-place