题目描述:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1], 其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1],不能使用除法。
对于这个题目,如果没有“不能使用除法”这个规定,可以通过计算A[0]A[1]…A[i]…*A[n-1]除以A[i]来计算B[i]的值(考虑A[i]是否为0的情况)
现在多了这个条件,我们可以这么考虑,如下面的图
对以上图片做描述:可以看出,B[i]为 A数组除了A[i]外的所有元素的乘积。我们可以画出如上的图。比如上图的B[0]原本应等于除A[0]外 A数组的所有元素的乘积,也就是B[0]=A[1]*A[2]*A[3]*A[4] …*A[n-1],再比如B[1]=A[0]*A[2]*A[3]*A[4] …*A[n-1],B[3]=A[1]*A[2]*A[4] …*A[n-1]等等,都会出来一条分界线,如上图,那我们就可以以这条分界线为基准,将B[i]划分为两部分:分界线之前和分界线之后,再将二者相乘,不就是我们所求的B[i]吗?
至于为什么对角线是1,可以这么看:B[0] = 1乘以分界线后面的部分。
B[1] = A[0]乘以1再乘以后面的部分,也就是B[1]=A[0]*B[0],以此类推。
到最后一个B[n-1] = A[0]*A[1] …*A[n-2]。需要注意每一个1只是在相应的行上设想成1,因为本身不参与该行的乘积(乘积结果为B[i])
因此,会有两个循环,第一次循环算左边的下三角(蓝色部分),第二次循环算右边的上三角(绿色部分),最后结果为二者相乘。
注意到:
第一次循环应从【1,n-1】(因为B[0] = 1乘以后面的部分,只需要算后面的部分就可以可以了),第二次循环应从【n-2,0】(因为B[n-1]等于前面的部分乘以1,只需要算前面的部分就可以了)
接下来附上代码
class Solution {
public:
vector<int> multiply(const vector<int>& A) {
vector<int> B(A.size());
if(A.size() <= 0){
return B;
}
caculate(B,A);
return B;
}
void caculate(vector<int> &B, const vector<int>& A){
//下三角
B[0] = 1;
for(int i = 1; i < A.size(); ++i){
B[i] = A[i - 1] * B[i - 1];
}
int temp = 1;
//上三角
for(int j = A.size() - 2; j >= 0; --j){
temp *= A[j + 1];
B[j] *= temp;
}
return;
}
};