Solution: Product of Array Except Self
Let's solve the Product of Array Except Self problem using the Two Pointers pattern.
Statement#
You’re given an integer array, arr. Return a resultant array so that res[i] is equal to the product of all the elements of arr except arr[i].
Write an algorithm that runs in ) time without using the division operation.
Constraints:
-
arr.length -
arr[i] - The product of any prefix or suffix of
arris guaranteed to fit in a 32-bit integer.
Solution#
So far, you have probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and any implementation constraints.
Naive approach#
A naive approach would be to use nested loops to traverse the array. For each element, we traverse all the other elements and calculate their product, which will be stored in the corresponding index of the output array.
The time complexity of this approach is , since we’re using nested loops to traverse the array. The space complexity of this approach is , since we’re using a constant number of additional variables.
Optimized approach using Two Pointers#
The idea is that we can break down the problem into two parts: the product of elements to the left of each index and the product of elements to the right of each index. By maintaining two separate running products as we traverse the array from both ends, we can accumulate the product values to populate the res array. This approach eliminates the need for repeated multiplications and effectively calculates the product except for the element at the current index. The Two Pointers pattern is employed here to handle both the left and right products in a single traversal.
Here’s how the algorithm works:
-
Initialize the following variables that will assist us in performing the algorithm:
-
res: This array will be used to store the output. It is initialized to . -
l,r: These are the pointers used to traverse the array. They are initialized to the left and right ends of the array, respectively. -
left_product: This variable stores the product of the elements to the left of thelpointer. -
right_product: This variable stores the product of the elements to the right of therpointer.
-
-
Traverse the array while the
landrpointers are not out of bounds:-
Calculate the product to the left of
nums[l]and store it inres[l]using the following formula:res[l] = res[l] * left_product -
Calculate the product to the right of the
nums[r]and store it inres[r]using the following formula:res[r] = res[r] * right_product -
Update
left_productto include the current element,nums[l], in the accumulated product for the next iteration. -
Update
right_productto include the current element,nums[r], in the accumulated product for the next iteration. -
Finally, increment the
lpointer and decrement therpointer to evaluate the next elements. -
The steps above are repeated until the
landrpointers go out of bounds.
-
When
l == r, both pointers point to the middle element of the array. For this element, both the products to its left and right are being computed one after another and stored inres[l](orres[r]sincel == rin this case). Therefore, for the case of the middle element, the final product of all the elements, excluding it, is computed in one step. -
After the
landrpointers cross each other, the following behavior occurs: -
The
lpointer computes the product to the left ofnums[l]as expected, but now the product to the right ofnums[l]has already been computed in a previous iteration by therpointer. Now both the right and left products have been calculated and combined, the resultant product in this entry is the final product of all the elements, excluding the current one. -
The
rpointer computes the product to the right ofnums[r]as expected, but now the product to the left ofnums[r]has already been computed in a previous iteration by thelpointer. Now both the right and left products have been calculated and combined, the resultant product in this entry is the final product of all the elements, excluding the current one.
-
-
Lastly, the
resarray contains the desired result, so return it.
The slides below illustrate how the algorithm runs:
1 of 13
2 of 13
3 of 13
4 of 13
5 of 13
6 of 13
7 of 13
8 of 13
9 of 13
10 of 13
11 of 13
12 of 13
13 of 13
Let’s look at the code for this solution below:
Solution summary#
The solution can be summarized in the following steps:
-
Create a list with the same length as the input list, initialized with s.
-
Keep track of products on the left and right sides of the current element.
-
Use two pointers—one starting from the beginning and the other from the end of the list.
-
Multiply and update values in the output array based on accumulated products and current element values.
-
Move the pointers toward each other to process the entire list.
Time complexity#
The time complexity of this solution is , since both the pointers simultaneously traverse the length of the array once.
Space complexity#
The space complexity of this solution is , since it doesn’t use any additional array for computations but only constant additional space.
Product of Array Except Self
Sort Colors