Problem Overview
LeetCode 238 gives you an integer array nums of length n. You must return an array answer where answer[i] equals the product of every element in nums except nums[i] itself. For example, given [1, 2, 3, 4] the output is [24, 12, 8, 6]: each position holds the product of all other elements.
The problem explicitly forbids using division and requires O(n) time. The follow-up challenge asks you to solve it using O(1) extra space (not counting the output array, which does not count as extra space per the problem statement).
Key constraints and facts to keep in mind before designing your solution:
- 2 <= nums.length <= 100,000 — brute-force O(n^2) will time out
- nums[i] can be -30 to 30 — negatives are allowed, zeros are allowed
- Division is explicitly forbidden — you cannot take the total product and divide
- The output array does not count as extra space per the problem
- Follow-up: achieve O(1) extra space beyond the output array
Why Division Fails
The tempting shortcut is to compute the total product of all elements and then divide by nums[i] for each position. When no zeros are present this works, but zeros break the approach in two distinct ways: if exactly one element is zero, only the position of that zero has a nonzero answer; if two or more elements are zero, every answer is zero.
Handling these cases correctly requires multiple conditional branches, tracking zero counts, and special-casing the index of the zero element. Even ignoring the problem's explicit ban on division, this leads to messy and error-prone code that is hard to verify in an interview setting.
More fundamentally, the prefix/suffix product approach is cleaner, more general, and maps directly onto the problem structure. It avoids division entirely and handles all zero configurations naturally without any extra logic.
Skip the Division Approach
The prefix/suffix approach is cleaner and more general than division with zero-handling. Even if the problem allowed division, the two-pass product pattern is the answer interviewers are looking for — it extends naturally to related problems like prefix sums and running products.
Two-Pass Prefix and Suffix
The key observation is that answer[i] = (product of all elements to the left of i) * (product of all elements to the right of i). These two parts can be computed independently in two linear passes, then multiplied together element-wise.
First pass (left to right): build a prefix array where prefix[i] holds the product of nums[0] through nums[i-1]. By convention prefix[0] = 1 because there are no elements to the left of index 0. Second pass (right to left): build a suffix array where suffix[i] holds the product of nums[i+1] through nums[n-1]. Again suffix[n-1] = 1 by convention.
The final answer at each position is simply prefix[i] * suffix[i]. Both arrays are O(n) in size, and each pass is O(n) in time, giving an overall O(n) time and O(n) space solution. The O(1) space optimization eliminates the need for a separate suffix array.
- 1Allocate prefix array of length n; set prefix[0] = 1
- 2Left pass: for i from 1 to n-1, set prefix[i] = prefix[i-1] * nums[i-1]
- 3Allocate suffix array of length n; set suffix[n-1] = 1
- 4Right pass: for i from n-2 down to 0, set suffix[i] = suffix[i+1] * nums[i+1]
- 5Build answer: answer[i] = prefix[i] * suffix[i] for each i
O(1) Extra Space Optimization
The O(1) space trick reuses the output array for the prefix products in the first pass, then sweeps right to left with a single integer variable tracking the running suffix product. This eliminates the separate suffix array entirely.
First pass: use the output array itself to store prefix products exactly as described above — answer[0] = 1, answer[i] = answer[i-1] * nums[i-1]. Second pass: initialize a variable suffix = 1. Traverse from right to left: multiply answer[i] by suffix, then update suffix = suffix * nums[i]. After both passes, answer[i] holds the correct result.
Because the output array is declared "free" by the problem, and the only additional storage is the single suffix integer variable, the extra space is O(1). This is the solution that impresses interviewers and earns full marks on the follow-up.
Output Array is Free Space
This is a common interview trick: the output array is 'free' space per the problem, so building the answer in-place during the first pass gives O(1) extra. The only extra variable needed is the running suffix integer in the second pass.
Walk-Through Example — [1, 2, 3, 4]
Starting with nums = [1, 2, 3, 4]. First pass (left to right): answer starts as [1, 1, 1, 1]. At i=1: answer[1] = answer[0] * nums[0] = 1 * 1 = 1. At i=2: answer[2] = answer[1] * nums[1] = 1 * 2 = 2. At i=3: answer[3] = answer[2] * nums[2] = 2 * 3 = 6. After left pass: answer = [1, 1, 2, 6].
Second pass (right to left): initialize suffix = 1. At i=3: answer[3] *= suffix → 6 * 1 = 6; suffix *= nums[3] → 1 * 4 = 4. At i=2: answer[2] *= suffix → 2 * 4 = 8; suffix *= nums[2] → 4 * 3 = 12. At i=1: answer[1] *= suffix → 1 * 12 = 12; suffix *= nums[1] → 12 * 2 = 24. At i=0: answer[0] *= suffix → 1 * 24 = 24; suffix *= nums[0] → 24 * 1 = 24.
Final answer: [24, 12, 8, 6]. Verification: 24 = 2*3*4, 12 = 1*3*4, 8 = 1*2*4, 6 = 1*2*3. All correct. The trace makes clear that the left pass accumulates running left products and the right pass multiplies in running right products — together they cover all elements except the current index.
- 1Left pass: answer = [1, 1, 2, 6] — each index holds the product of all elements to its left
- 2Init suffix = 1; at i=3: answer[3] = 6*1 = 6, suffix = 4
- 3At i=2: answer[2] = 2*4 = 8, suffix = 12
- 4At i=1: answer[1] = 1*12 = 12, suffix = 24
- 5At i=0: answer[0] = 1*24 = 24, suffix = 24
- 6Final: [24, 12, 8, 6] — verified correct
Code Walkthrough — Python and Java
Python: def productExceptSelf(nums): n = len(nums); answer = [1] * n — left pass: for i in range(1, n): answer[i] = answer[i-1] * nums[i-1] — right pass: suffix = 1; for i in range(n-2, -1, -1): answer[i] *= suffix; suffix *= nums[i] — return answer. Two simple loops, O(n) time, O(1) extra space.
Java: public int[] productExceptSelf(int[] nums) { int n = nums.length; int[] answer = new int[n]; Arrays.fill(answer, 1); for (int i = 1; i < n; i++) answer[i] = answer[i-1] * nums[i-1]; int suffix = 1; for (int i = n-2; i >= 0; i--) { answer[i] *= suffix; suffix *= nums[i]; } return answer; }. Identical logic, same two passes, fully O(1) extra space.
Both solutions handle all edge cases cleanly: arrays containing zeros (no special casing needed), negative numbers (products work naturally), and n = 2 (each pass executes exactly once). The code is concise, readable, and straightforward to explain during an interview.
Initialize to 1, Not 0
Initialize the running suffix variable to 1, not 0. Since we are multiplying — not adding — starting from 0 would wipe out every product. Similarly the output array is initialized to all 1s so the prefix product chain starts correctly at the identity element for multiplication.