题目链接
题目描述
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例 1:
输入:
nums = [1,2,3,4]
输出:
[24,12,8,6]
示例 2:
输入:
nums = [-1,1,0,-3,3]
输出:
[0,0,9,0,0]
提示:
2 <= nums.length <= 10^5
-30 <= nums[i] <= 30 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
超时的方法
两个for循环,而题目的0=<nums.length<=10^5,所以肯定会超时
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int a=nums.size();
vector<int> v(a, 1);
for(int i=0; i<a; i++){
for(int j=0; j<a; j++){
if(j!=i)
v[i]*=nums[j];
}
}
return v;
}
};
法1
首先题目说不能使用除法,我们如果使用了除法会怎么样呢,通过了
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int a=nums.size();
vector<int> v(a, 1);
int b=1;
for(int i=0; i<a; i++){
b*=nums[i];
}
for(int i=0; i<a; i++){
if(nums[i]!=0)
v[i]=b/nums[i];
else{
for(int j=0; j<a; j++)
if(j!=i)
v[i]*=nums[j];
}
}
return v;
}
};
法2
注意这里的vlr[i]指的是前i项的乘积,
vrl[j]指的是第j项开始所有往后的项的乘积。
主要思想来源于超时的方法,首先要知道为什么超时,就是因为有太多的重复计算了,我们现在就要通过另外两个数组把乘积先存起来,这样就不会重复计算了,乘积只计算了一次。
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int a=nums.size();
vector<int> v(a, 1);
int b=1;
vector<int> vlr(a+1, 1);
vector<int> vrl(a+1, 1);
vlr[0]=nums[0];
vrl[a-1]=nums[a-1];
for(int i=1; i<a; i++){
vlr[i]=vlr[i-1]*nums[i];
}
for(int j=a-1; j>=0; j--){
vrl[j]=vrl[j+1]*nums[j];
}
for(int i=0; i<a; i++){
if(i==0){
v[i]=vrl[i+1];
}
else if(i==a-1){
v[i]=vlr[i-1];
}
else{
v[i]=vlr[i-1]*vrl[i+1];
}
}
return v;
}
};
法3
题目最后面还有一个进阶的描述,空间复杂度是O(1),而且说输出数组不算入时间复杂度。这样的话我们就利用一下输出的数组:先让它存储上一种方法中的vlr,然后再来一个逆向的循环,让r存储上一种方法中的vrl,就好了。
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int a=nums.size();
vector<int> v(a, 1);
int b=1;
for(int i=1; i<a; i++){
v[i]=v[i-1]*nums[i-1];
}
int r=1;
for(int j=a-1; j>=0; j--){
v[j]=v[j]*r;
r*=nums[j];
}
return v;
}
};
希望大家在看到我的解释之后能够直接了解,同时如果有错误的话请指出,共勉。