给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
提示:
所有元素乘积之和不会溢出 32 位整数
a.length <= 100000来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/gou-jian-cheng-ji-shu-zu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
如果是使用下面嵌套遍历两次的话,时间复杂度就会变成O(N^2),会超时
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
vector<int> result;
for(int i=0;i<a.size();i++)
{
int tmp=1;
for(int j=0;j<a.size();j++)
{
if(j==i)
{
continue;
}
else
{
tmp*=a[j];
}
}
result.push_back(tmp);
}
return result;
}
};
我们转换一下思路,求除了当前位置的元素的相乘结果就是求当前元素左侧的所有元素的相乘结果乘上当前元素右侧的所有元素的相乘结果
1 | 2 | 3 | 4 | 5 |
当前元素的左边的所有数据相乘
1 | 1 | 2 | 6 | 24 |
当前元素的右边的所有数据相乘
120 | 60 | 20 | 5 | 1 |
上面的两张表格对应位置的元素相乘
120 | 60 | 40 | 30 | 24 |
也就得到了我们的结果
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
int size=a.size();
if(size==0)
{
return a;
}
vector<int> left(size,0);
//第一个位的初始值赋值为1
left[0]=1;
vector<int> right(size,0);
//最后一个位的初始值赋值为1
right[size-1]=1;
vector<int> result;
//将当前位左侧的元素全部都相乘,计算出结果
for(int i=1;i<size;i++)
{
left[i]=a[i-1]*left[i-1];
}
//将当前位右侧的元素全部都相乘,计算出结果
for(int i=size-2;i>=0;i--)
{
right[i]=a[i+1]*right[i+1];
}
//我们的结果集就是当前元素的左侧元素乘上右侧的元素
for(int i=0;i<size;i++)
{
result.push_back(left[i]*right[i]);
}
return result;
}
};
对于上面那种方法我们可以进行优化,采用双指针的方式从左右两边同时遍历,右指针所存储的是当前元素右边的所有元素的相乘的结果,左指针所存储的是当前元素左侧所有的元素相乘的结果。
初始情况
1 | 2 | 3 | 4 | 5 |
结果数组
1 | 1 | 1 | 1 | 1 |
left=1,right=1
遍历第一遍
1 | 2 | 3 | 4 | 5 |
结果数组
1 | 1 | 1 | 1 | 1 |
left=1,right=5
遍历第二遍
1 | 2 | 3 | 4 | 5 |
结果数组
1 | 1 | 1 | 5 | 1 |
left=2,right=20
遍历第三遍
1 | 2 | 3 | 4 | 5 |
结果数组
1 | 1 | 40 | 5 | 1 |
left=6,right=60
遍历第四遍
1 | 2 | 3 | 4 | 5 |
结果数组
1 | 60 | 40 | 30 | 1 |
left=24,right=120
遍历第五遍
1 | 2 | 3 | 4 | 5 |
结果数组
120 | 60 | 40 | 30 | 24 |
也就是得到了我们的最终结果
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
int size=a.size();
vector<int> result(size,1);
//我们的左指针存储的是当前元素左侧的所有元素的相乘结果
int left=1;
//我们的右指针存储的是当前元素右侧的所有元素的相乘结果
int right=1;
for(int i=0;i<size;i++)
{
//从左向右乘上左指针中的数据
result[i]*=left;
//从右向左乘上右指针中的数据
result[size-i-1]*=right;
//更新左右指针
left*=a[i];
right*=a[size-i-1];
}
return result;
}
};