|
| 1 | +--- |
| 2 | +id: product-of-array-except-self |
| 3 | +title: Product of Array Except Self(LeetCode) |
| 4 | +sidebar_label: 0238-Product of Array Except Self |
| 5 | +tags: |
| 6 | + - Array |
| 7 | + - Prefix Sum |
| 8 | +description: 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]. |
| 9 | +--- |
| 10 | + |
| 11 | +## Problem Statement |
| 12 | + |
| 13 | +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]`. |
| 14 | + |
| 15 | +The product of any prefix or suffix of `nums` is guaranteed to fit in a 32-bit integer. |
| 16 | + |
| 17 | +You must write an algorithm that runs in `O(n)` time and without using the division operation. |
| 18 | + |
| 19 | +### Examples |
| 20 | + |
| 21 | +**Example 1:** |
| 22 | + |
| 23 | +```plaintext |
| 24 | +Input: nums = [1,2,3,4] |
| 25 | +Output: [24,12,8,6] |
| 26 | +``` |
| 27 | + |
| 28 | +**Example 2:** |
| 29 | + |
| 30 | +```plaintext |
| 31 | +Input: nums = [-1,1,0,-3,3] |
| 32 | +Output: [0,0,9,0,0] |
| 33 | +``` |
| 34 | + |
| 35 | +### Constraints |
| 36 | + |
| 37 | +- `2 <= nums.length <= 105` |
| 38 | +- `30 <= nums[i] <= 30` |
| 39 | +- The product of any prefix or suffix of `nums` is guaranteed to fit in a 32-bit integer. |
| 40 | + |
| 41 | +## Solution |
| 42 | + |
| 43 | +We can solve this problem using multiple approaches. Here, I have explained all the possible solutions: |
| 44 | + |
| 45 | +1. Brute Force Approach: Using nested loops to calculate the product of elements except for the current index. |
| 46 | +2. Dynamic Programming (Tabulation): Using two arrays to store the left and right products. |
| 47 | +3. Dynamic Programming (Space Optimization): Optimizing space usage by combining the two product arrays into a single array. |
| 48 | + |
| 49 | +### Approach Brute Force (Two Nested Loops) |
| 50 | + |
| 51 | +### Algorithm |
| 52 | +1. Initialize an empty vector `output`. |
| 53 | +2. Iterate through each element `i` in the array `nums`: |
| 54 | +* Set `product` to 1. |
| 55 | +* Iterate through each element `j` in the array `nums`: |
| 56 | + * If `i` equals `j`, skip this iteration. |
| 57 | + * Multiply `product` by `nums[j]`. |
| 58 | +* Append `product` to the `output` vector. |
| 59 | +3. Return the `output` vector. |
| 60 | + |
| 61 | +#### Implementation |
| 62 | + |
| 63 | +```C++ |
| 64 | +class Solution { |
| 65 | +public: |
| 66 | + vector<int> productExceptSelf(vector<int>& nums) { |
| 67 | + int n = nums.size(); |
| 68 | + vector<int> output; |
| 69 | + for(int i = 0; i < n; i++) { |
| 70 | + int product = 1; |
| 71 | + for(int j = 0; j < n; j++) { |
| 72 | + if(i == j) continue; |
| 73 | + product *= nums[j]; |
| 74 | + } |
| 75 | + output.push_back(product); |
| 76 | + } |
| 77 | + return output; |
| 78 | + } |
| 79 | +}; |
| 80 | +``` |
| 81 | +
|
| 82 | +### Complexity Analysis |
| 83 | +
|
| 84 | +- **Time complexity**: O(N^2) - Two nested loops create a quadratic time complexity. |
| 85 | +- **Space complexity**: O(1) - No extra space except for the output array (which doesn't count towards space complexity). |
| 86 | +
|
| 87 | +### Approach 2: Dynamic Programming (Tabulation) |
| 88 | +
|
| 89 | +#### Algorithm |
| 90 | +
|
| 91 | +1. Initialize vectors `left_Product` and `right_Product` of size `n` with all elements set to 1. |
| 92 | +2. Calculate `left_Product`: |
| 93 | +* Set `left_Product[0]` to 1. |
| 94 | +* For each element `i` from 1 to `n-1`, set `left_Product[i]` to `left_Product[i-1]` multiplied by `nums[i-1]`. |
| 95 | +3. Calculate `right_Product`: |
| 96 | +* Set `right_Product[n-1]` to 1. |
| 97 | +* For each element `i` from `n-2` to 0, set `right_Product[i]` to `right_Product[i+1]` multiplied by `nums[i+1]`. |
| 98 | +4. Initialize vector `ans` of size `n`. |
| 99 | +5. For each element `i` from 0 to `n-1`, set `ans[i]` to `left_Product[i]` multiplied by `right_Product[i]`. |
| 100 | +6. Return the `ans` vector. |
| 101 | + |
| 102 | +#### Implementation |
| 103 | +
|
| 104 | +```C++ |
| 105 | +class Solution { |
| 106 | +public: |
| 107 | + vector<int> productExceptSelf(vector<int>& nums) { |
| 108 | + int n = nums.size(); |
| 109 | + vector<int> ans(n); |
| 110 | + vector<int> left_Product(n); |
| 111 | + vector<int> right_Product(n); |
| 112 | +
|
| 113 | + left_Product[0] = 1; |
| 114 | + for(int i = 1; i < n; i++) { |
| 115 | + left_Product[i] = left_Product[i-1] * nums[i-1]; |
| 116 | + } |
| 117 | +
|
| 118 | + right_Product[n-1] = 1; |
| 119 | + for(int i = n-2; i >= 0; i--) { |
| 120 | + right_Product[i] = right_Product[i+1] * nums[i+1]; |
| 121 | + } |
| 122 | +
|
| 123 | + for(int i = 0; i < n; i++) { |
| 124 | + ans[i] = left_Product[i] * right_Product[i]; |
| 125 | + } |
| 126 | + return ans; |
| 127 | + } |
| 128 | +}; |
| 129 | +``` |
| 130 | + |
| 131 | +### Complexity Analysis |
| 132 | + |
| 133 | +- **Time complexity**: O(N) - We iterate through the array three times. |
| 134 | +- **Space complexity**: O(N) - Two additional arrays (left_Product and right_Product) are used. |
| 135 | + |
| 136 | +### Approach 3: Dynamic Programming (Space Optimization) |
| 137 | + |
| 138 | +#### Algorithm |
| 139 | + |
| 140 | +1. Initialize a vector `output` of size `n` with all elements set to 1. |
| 141 | +2. Calculate the left product: |
| 142 | +* Set `output[0]` to 1. |
| 143 | +* For each element `i` from 1 to `n-1`, set `output[i]` to `output[i-1]` multiplied by `nums[i-1]`. |
| 144 | +3. Calculate the right product: |
| 145 | +* Initialize `right` to 1. |
| 146 | +* For each element `i` from `n-1` to 0, set `output[i]` to `output[i]` multiplied by right, then set `right` to `right` multiplied by `nums[i]`. |
| 147 | +4. Return the `output` vector. |
| 148 | + |
| 149 | +#### Implementation |
| 150 | + |
| 151 | +```C++ |
| 152 | +class Solution { |
| 153 | +public: |
| 154 | + vector<int> productExceptSelf(vector<int>& nums) { |
| 155 | + int n = nums.size(); |
| 156 | + vector<int> output(n); |
| 157 | + |
| 158 | + output[0] = 1; |
| 159 | + for(int i = 1; i < n; i++) { |
| 160 | + output[i] = output[i-1] * nums[i-1]; |
| 161 | + } |
| 162 | + |
| 163 | + int right = 1; |
| 164 | + for(int i = n-1; i >= 0; i--) { |
| 165 | + output[i] *= right; |
| 166 | + right *= nums[i]; |
| 167 | + } |
| 168 | + return output; |
| 169 | + } |
| 170 | +}; |
| 171 | +``` |
| 172 | + |
| 173 | +### Complexity Analysis |
| 174 | + |
| 175 | +- **Time complexity**: O(N) - We iterate through the array twice. |
| 176 | +- **Space complexity**: O(1) - Constant space is used, except for the output array. |
| 177 | + |
| 178 | +### Conclusion |
| 179 | + |
| 180 | +By exploring various approaches to solve this problem, we can see that the brute force method, while simple, is inefficient with a time complexity of O(N^2). The dynamic programming approach with tabulation optimizes the time complexity to O(N) but uses extra space. The most optimized approach uses space-efficient dynamic programming, maintaining O(N) time complexity while reducing space complexity to O(1). This final approach is the best in terms of both time and space efficiency. |
0 commit comments