Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
answer[i] = product of everything left of i × product of everything right of i. Compute prefix products in one left-to-right pass, then multiply by suffix products in a right-to-left pass, reusing the output array so it's O(1) extra space. Division is banned (and breaks on zeros), so the two-pass prefix/suffix trick is the intended answer. O(n) time.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you can avoid division and still hit O(n) by precomputing left and right partial products, and whether you can squeeze extra space to O(1) using the output array.
Where candidates slip
Reaching for total-product ÷ nums[i] (fails on zeros and is explicitly forbidden), or using separate prefix and suffix arrays without collapsing them.
How to stand out
Derive the two-pass solution from the definition, handle the zero cases by construction (no special-casing needed), and note the output array doesn't count as extra space.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachExplore the full treeCollapse the tree
How to read it:Each answer cell is the left running product times the right running product.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Division (Why It Fails)
1Hint 1Explore hintHide hint
The naive idea: compute the total product, then divide by each element.
2Hint 2Explore hintHide hint
What happens when an element is 0? And the problem forbids division anyway.
3Hint 3Explore hintHide hint
Use this to motivate a division-free O(n) method.
A · Core idea
The tempting shortcut is total = ∏ nums, then answer[i] = total / nums[i]. It's O(n) and tiny — but it's disqualified for two reasons. First, the problem bans the division operator outright. Second, it breaks on zeros: if one element is 0 you'd divide by zero, and if two elements are 0 every answer should be 0 but the formula can't express that cleanly.
Takeaway. Naming this and explaining why it's rejected demonstrates you understood the constraints, then pivots naturally to the prefix/suffix solution.
C · Code with teaching comments
Reference implementation preview// Rejected: division is forbidden AND undefined when nums[i] == 0. public int[] productExceptSelf(int[] nums) { int total = 1; for (int n : nums) total *= n; // breaks: total becomes 0 if any zero int[] res = new int[nums.length];Explore the full codeHide the full code
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The zero cases are the real lesson: when division is unsafe, replace 'undo a global aggregate' with 'build the aggregate from the sides'. That reframing is the prefix/suffix idea.
ComplexityO(n) time, O(1) space — Two linear passes, but it's invalid: division is disallowed and undefined for zeros.
E · Edge cases and pitfalls2Submitting division and getting rejected by the no-division rule.Explore edge casesHide edge cases
Pitfalls
- Submitting division and getting rejected by the no-division rule.
- Crashing or producing wrong output when the array contains one or more zeros.
Approach 2 of 2 · Optimal
Prefix × Suffix in One Array (Optimal)
1Hint 1Explore hintHide hint
answer[i] = (product of everything left of i) × (product of everything right of i). Can you precompute those?
2Hint 2Explore hintHide hint
Do a left-to-right pass writing the running prefix product into answer[i] (before multiplying in nums[i]).
3Hint 3Explore hintHide hint
Then a right-to-left pass: keep a running suffix product scalar and multiply it into answer[i] before folding nums[i] into the suffix.
A · Core idea
Define answer[i] as the product of all elements to the left of i times the product of all elements to the right. Build it in two passes:
- 1Left pass. Maintain
prefix = 1. For eachifrom left to right, setanswer[i] = prefix(the product of everything strictly beforei), then updateprefix *= nums[i]. Crucially we write before multiplying, soanswer[i]never includesnums[i]. - 2Right pass. Maintain
suffix = 1. For eachifrom right to left, multiplyanswer[i] *= suffix, then updatesuffix *= nums[i]. Nowanswer[i]holds prefix×suffix — exactly the product of all-but-self.
Why zeros just work. If nums[k] = 0, then for any i ≠ k either the prefix or suffix passes through index k and carries the zero, making answer[i] = 0. Only answer[k] skips its own zero and survives. No special-casing needed — the structure handles it.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
nums = [1, 2, 3, 4]Array state
after left pass
res holds prefixes
[24, 12, 8, 6]C · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The output array doubles as scratch space for the prefix pass, so the only extra memory is the suffix scalar. This 'write the partial aggregate into the result, then fold in the other direction' is the reusable shape behind many prefix/suffix problems.
ComplexityO(n) time, O(1) space — Two linear passes = O(n). The output array holds prefixes (doesn't count), and the suffix is a single scalar → O(1) extra space.
E · Edge cases and pitfalls5nums = [0, 4, 0] — Two zeros → every answer is 0, including the zero positions (each has the other zero on one side).Explore edge casesHide edge cases
Edge cases handled
nums = [0, 4, 0]Two zeros → every answer is 0, including the zero positions (each has the other zero on one side).nums = [-1, 1, 0, -3, 3]Single zero → only its index gets the product of the rest (9); all others are 0.
Pitfalls
- Multiplying nums[i] into prefix BEFORE writing res[i] — then answer[i] wrongly includes itself.
- Allocating separate prefix[] and suffix[] arrays — correct but misses the O(1)-space follow-up.
- Initializing prefix/suffix to 0 instead of 1 — zeros out every product.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic int[] productExceptSelf(int[] nums) { int n = nums.length; int[] res = new int[n]; int prefix = 1; for (int i = 0; i < n; i++) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Writing the cell after folding in nums[i]
If you multiply nums[i] into prefix before assigning res[i], the cell includes the element itself, which is exactly what 'except self' forbids.
Explore the code comparisonHide the code comparison
Writing the cell after folding in nums[i]
If you multiply nums[i] into prefix before assigning res[i], the cell includes the element itself, which is exactly what 'except self' forbids.
Don't write this
prefix *= nums[i];
res[i] = prefix; // now includes nums[i] — wrongWrite this instead
res[i] = prefix; // product of everything before i
prefix *= nums[i];2Two extra arrays when O(1) space is asked
Separate prefix[] and suffix[] arrays are O(n) extra space. Store prefixes in the output array and carry the suffix as a single scalar to meet the follow-up.
Explore the code comparisonHide the code comparison
Two extra arrays when O(1) space is asked
Separate prefix[] and suffix[] arrays are O(n) extra space. Store prefixes in the output array and carry the suffix as a single scalar to meet the follow-up.
Don't write this
prefix = [...]; suffix = [...]
res = [prefix[i] * suffix[i] for i in range(n)]Write this instead
res = [1]*n
# left pass writes prefixes into res, right pass multiplies a scalar suffixRevise
Carry the pattern into the interview
Pattern to remember
Prefix × suffix products (no division)
Code pattern to memorize
res[i] = 1
prefix = 1
for i in range(n): res[i] = prefix; prefix *= nums[i]
suffix = 1
for i in range(n-1,-1,-1): res[i] *= suffix; suffix *= nums[i]Rules to remember
- 1
answer[i]= (product of all left of i) × (product of all right of i) — never includesnums[i]. - 2No division — it's banned and undefined when any element is 0.
- 3Write the prefix into
reson the way right, then multiply by the running suffix on the way left. - 4Reuse the output array for prefixes so the running suffix scalar is the only extra state →
O(1)extra space. - 5Seed both running products at 1 (multiplicative identity), and
res[0]'s prefix is 1 (nothing to its left).
Use this pattern when
- Each output depends on 'everything except me' aggregated multiplicatively or additively
- Division is disallowed or unsafe (zeros, modular arithmetic)
- You can precompute left/right partial aggregates in linear passes
Choose another pattern when
- Division is allowed and no zeros → total product ÷ nums[i] is simpler
- Need contiguous-subarray products → Maximum Product Subarray (DP), not prefix/suffix
- Need sums not products of all-but-self → same prefix/suffix idea but additive
Interview takeaway
Prefix/suffix accumulation answers any 'combine everything except index i' question in O(n) without division. The same two-pass scaffold underlies trapping rain water and many range-aggregate problems.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternPrefix/suffix accumulation. Reach for it when each output combines 'everything except index i', especially when division is disallowed or unsafe. The two-pass scaffold reappears in Trapping Rain Water and range-aggregate problems.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Maximum Product SubarrayComing soonContiguous products with sign flips — track running max and min (DP).
- Range Sum Query — ImmutableComing soonAdditive prefix sums answer range queries in O(1).
- Trapping Rain WaterUses left-max / right-max prefix-suffix arrays, same two-pass scaffold.