Product of Array Except Self Solution
Given an integer array nums, return an array answer where answer[i] is the product of all elements except nums[i]. You must solve it without using division and in O(n) time.
Problem Statement
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 algorithm must run in O(n) time and must not use the division operation.
Brute Force โ O(nยฒ)
For each index i, multiply all other elements together. Two nested loops โ the outer selects the position, the inner computes the product of everything except that position.
Directly implements the definition: answer[i] = โ nums[j] for all j โ i. Correct by construction โ every non-self element is multiplied.
i overlaps heavily with index i-1. Prefix and suffix products precompute these running products, reducing repeated work from O(n) per element to O(1).
| Metric | Value |
|---|---|
| Time | O(nยฒ) โ n multiplications per element |
| Space | O(1) โ excluding the output array |
Prefix & Suffix Products โ O(n)
The product of all elements except nums[i] equals product of everything to the left ร product of everything to the right. Compute running prefix products left-to-right, then multiply in suffix products right-to-left โ all in the output array itself.
- Step 1: Initialize
answer[i] = 1for all i. - Step 2: Left pass โ maintain a running
prefix = 1. For each i from 0 to nโ1: setanswer[i] = prefix, thenprefix *= nums[i]. - Step 3: Right pass โ maintain a running
suffix = 1. For each i from nโ1 to 0: setanswer[i] *= suffix, thensuffix *= nums[i]. - Step 4: Return
answerโ each slot now holds left-product ร right-product.
- Any time a problem asks for a value that depends on all other elements (excluding the current one) โ think prefix/suffix decomposition.
- The signal is "for each index, compute something from left side AND right side." This pattern appears in LC 238, LC 42 (Trapping Rain Water โ prefix max + suffix max), LC 135 (Candy โ left and right passes), and range-product queries.
- The output array itself stores the prefix products from the left pass.
- The right pass multiplies suffix products directly into the output.
- We only need one extra variable (
suffix) as we sweep right-to-left โ achieving O(1) extra space beyond the required output.
Visual Walkthrough
Trace through nums = [1, 2, 3, 4]:
- Two linear passes โ no nested loops.
- The left pass builds "product of everything before me." The right pass multiplies in "product of everything after me." Each element's final value is left ร right โ the product of all others.
Code โ Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Brute Force | O(nยฒ) | O(1) | Correct but too slow for n = 10โต |
| Total Product รท current | O(n) | O(1) | Violates the "no division" constraint; fails on zeros |
| Prefix/Suffix โ optimal | O(n) | O(1)* | Two passes, no division. *O(1) extra beyond output array. |
- Division seems tempting โ compute total product, then
answer[i] = total / nums[i]. - But: (1) the problem explicitly forbids it, (2) zeros break it โ dividing by zero is undefined, and you'd need special-case handling for one or more zeros.
- The prefix/suffix approach handles zeros naturally because it never divides.
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Contains one zero | [1, 2, 0, 4] | Only the zero's position gets a non-zero product (1ร2ร4=8). All others become 0. |
| Contains two zeros | [0, 2, 0, 4] | Every position includes at least one zero โ entire answer is [0, 0, 0, 0]. |
| Negative numbers | [-1, 2, -3, 4] | Sign handling is automatic โ multiplication preserves sign correctly. |
| Two elements | [3, 5] | Minimum input. answer = [5, 3] โ each is the other's value. |
| All ones | [1, 1, 1, 1] | Every product is 1. Prefix/suffix stays 1 throughout โ the identity case. |
| Large array | n = 10โต, values in [-30, 30] | Guaranteed to fit in 32-bit int per constraints. No overflow concern. |
prefix into answer[i] before multiplying prefix *= nums[i]. If you multiply first, you include nums[i] in its own product. The correct sequence is: store, then update. Same rule applies in the right pass.