LeetCode 238: Product of Array Except Self
Matozinho / October 14, 2023
6 min read
Description
A deep dive into the solution for LeetCode's 'Product of Array Except Self' problem.
Problem: Product of Array Except Self
LeetCode problem 238, Product of Array Except Self, requires us to compute an output array such that each element at index i
in the output array is the product of all elements of the input array nums
except nums[i]
. This needs to be done in O(n) time complexity and without using the division operation.
Problem Summary
Given an integer array nums
, return an array answer
such that answer[i]
is the product of all the elements of nums
except nums[i]
.
Example 1:
- Input:
nums = [1, 2, 3, 4]
- Output:
[24, 12, 8, 6]
Example 2:
- Input:
nums = [-1, 1, 0, -3, 3]
- Output:
[0, 0, 9, 0, 0]
Constraints:
2 <= nums.length <= 10^5
-30 <= nums[i] <= 30
- The product of any prefix or suffix of
nums
is guaranteed to fit in a 32-bit integer.
Insights and Approach
We can’t use division, so a straightforward approach of dividing the total product by each element isn’t viable. Instead, the key to solving this problem efficiently is to leverage prefix and suffix products.
- Prefix product: The product of all elements before a given index.
- Suffix product: The product of all elements after a given index.
By precomputing prefix and suffix products, we can calculate the product of all elements except the current one for each index in linear time.
Initial Implementation
My first approach involved using two arrays (left_acumulator
and right_acumulator
) to store the prefix and suffix products, respectively. Then, I computed the result using these arrays.
Code:
Explanation:
- Populate the
left_acumulator
with prefix products. Each element at indexi
contains the product of all elements beforenums[i]
. - Populate the
right_acumulator
with suffix products, which stores the product of all elements afternums[i]
. - Combine the results from both accumulators to compute the final output. For each index
i
, the result is the product ofleft_acumulator[i-1]
andright_acumulator[i+1]
.
Issues with the First Approach:
This approach uses O(n)
space due to two auxiliary arrays (left_acumulator
and right_acumulator
).
There is also a slight inefficiency caused by reversing the right_acumulator
after populating it.
Optimized Implementation
In the second implementation, I improved the code by removing the need to reverse the right_acumulator
. I also preallocated arrays with the exact size required to avoid dynamic growing.
Explanation:
- Prefix and Suffix Computation: In this version, I compute the prefix and suffix products in the same manner but eliminate the need for reversing the suffix array by building it backward in-place.
- Efficiency: Preallocating the arrays saves time, and this approach still computes the result in
O(n)
time withO(n)
space complexity.
Issues with the Second Approach:
While this solution improves clarity and avoids reversing the array, it still uses extra space due to the prefix and suffix arrays.
Further Optimized Approach
For the third implementation, I aimed to minimize extra space usage by maintaining the prefix and suffix products in a single pass without storing separate arrays.
Explanation:
- Prefix Product: I first compute the prefix product for each element. Here,
prefix[i]
contains the product of all elements before indexi
(just like before). - Suffix Product On-the-Fly: Instead of storing the suffix products, I maintain a running
suffix
variable that holds the product of elements after the current index, updating it as I iterate from right to left. - Single Pass: By combining the prefix and suffix computation in one loop, the solution achieves
O(1)
extra space (excluding the result array).
Final Thoughts:
This final approach is the most optimized solution as it:
- Runs in
O(n)
time complexity. - Uses only
O(1)
extra space by avoiding the use of separate prefix and suffix arrays. - Efficiently computes the product of all elements except the current one in two passes over the array (one for prefix and one for suffix).
Conclusion
The Product of Array Except Self problem can be efficiently solved using prefix and suffix products. The final approach offers a clean and optimal solution with O(n) time complexity and O(1) extra space usage. By computing the prefix product first and then calculating the result with a running suffix product, we eliminate the need for extra space while still maintaining linear time efficiency.