文章目录
题目描述
给你一个长度为 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)