題目描述
給你一個長度爲 n 的整數數組 nums,其中 n > 1,返回輸出數組 output ,其中 output[i] 等於 nums 中除 nums[i] 之外其餘各元素的乘積。
示例:
輸入: [1,2,3,4]
輸出: [24,12,8,6]
提示:題目數據保證數組之中任意元素的全部前綴元素和後綴(甚至是整個數組)的乘積都在 32 位整數範圍內。
說明: 請不要使用除法,且在 O(n) 時間複雜度內完成此題。
進階:
你可以在常數空間複雜度內完成這個題目嗎?( 出於對空間複雜度分析的目的,輸出數組不被視爲額外空間。)
解題思路
題目要求時間複雜度爲O(n)
,因此不能用多重循環的方法解題。
題目要求不能用除法,因此不能用最終乘積除以每一個元素。
因此我們可以考慮最終結果爲該數左側的累積乘以該數右邊的累積。
即output[i] = left[i] * right[i]
一、空間複雜度O(n)
定義兩個數組left[]
和right[]
分爲記錄左側的累積和右側的累積,如下圖所示:(圖源LeetCode官方)
最後的結果利用output[i] = left[i] * right[i]
即可。
二、空間複雜度O(1)
由於題目要求,output數組不佔用空間,因此只用output數組即可。
第一遍遍歷,讓output數組中元素爲左側數字的累積。
第二遍遍歷,讓output直接賦值爲結果即可。
除此之外,還需要一個變量right在第二遍遍歷時記錄右側的累積。
具體實現細節請見代碼及註釋。
具體代碼
一、 空間複雜度O(n)
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
//定義輸出數組
vector<int>output;
//計算數組長度
int length = nums.size();
int left[length];//存放左邊整數乘積
int right[length];//存放右邊整數乘積
//邊緣元素初始化爲1
left[0] = 1;
right[length - 1] = 1;
//爲左邊的整數乘積賦值
for(int i = 1;i<length;i++){
left[i] = left[i-1] * nums[i-1];
}
//爲右邊的整數乘積賦值
for(int i = length - 2;i>=0;i--){
right[i] = right[i+1] * nums[i+1];
}
//爲輸出output賦值
for(int i =0;i<length;i++){
output.push_back(left[i] * right[i]);
}
return output;
}
};
二、空間複雜度O(1)
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
//計算數組長度
int length = nums.size();
//定義輸出數組,且只用這一個數組
vector<int>output(length);
//初始化最左邊的整數乘積爲1
output[0] = 1;
//爲左邊的整數乘積賦值
for(int i = 1;i<length;i++){
output[i] = output[i-1] * nums[i-1];
}
//利用一個變量記錄右邊整數乘積
int right = 1;
//爲output賦值
for(int i = length - 1;i>=0;i--){
output[i] *= right;
right *= nums[i];
}
return output;
}
};
性能結果
一、 空間複雜度O(n)
二、空間複雜度O(1)