目录


1.题目描述:

给定一个数组​​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]​​。不能使用除法。

2.解题思路:

  首先,仔细理解题意,​​B[i]​​是A数组所有元素的乘积,但是没有​​A[i]​​项,如果没有不能使用除法这一限制,我们可以直接将​​A​​数组的所有元素相乘,得到一个乘积,记为​​res​​,则使用公式​​B[i] = res/A[i]​​即可得到​​B​​这个乘积数组。

  现在有不能使用除法的限制,只能使用其他办法,当然,一个最直观的办法是每次计算​​B[i]​​时,都计算​​A​​数组中​​n-1​​个数字的乘积,显然这需要​​O(n^2)​​的时间复杂度。

  仔细分析可以发现,这种暴力解法有很多重复的计算,我们可以通过一个简单的改变来避免这些重复计算。具体如下:

  我们可以把​​B[i]=A[0]*A[1]*A[2]*···*A[i-1]*A[i+1]*···*A[n-1]​​看成是两部分的乘积,第一部分是i之前的所有项,记为​​C[i]​​,即​​C[i]=A[0]*A[1]*A[2]*···*A[i-1]​​,第二部分是​​i​​之后的所有项,记为​​D[i]​​,即​​D[i]=A[i+1]*···*A[n-1]​​。

  经过这样的分隔后,数组​​B​​就相当于可以用如下的矩阵来构建,​​B[i]​​为矩阵中第i行所有元素的乘积。

1.剑指Offer之构建乘积数组_数组

  由此,我们不难得出相应的规律:首先​​B[i]=C[i]*D[i]​​,而​​C[i]​​可以通过自上而下的顺序进行计算,即​​C[0]=1,C[i]=C[i-1]*A[i-1]​​,同理,​​D[i]​​可以通过自下而上的顺序进行计算,即​​D[len-1]=1,D[i]=D[i+1]*A[i+1]​​。

代码如下所示,第一个​​for​​循环从上而下相当于计算​​C[i]​​,第二个​​for​​循环自下而上相当于在​​C[i]​​的基础上乘以​​D[i]​​。显然时间复杂度为​​O(n)​​。

3.编程实现(Java):

public class multiplyArray_1 {
public int[] multiply(int[] A) {
if(A==null||A.length<1)
return A;
int len=A.length;
int[] B=new int[len];
B[0]=1;
for(int i=1;i<len;i++) //第一部分可以自上而下
B[i]=B[i-1]*A[i-1];

int temp=1; //temp用来保存第二部分
for(int i=len-2;i>=0;i--){ //第二部分可以自下而上
temp=temp*A[i+1];
B[i]=B[i]*temp;
}
return B;
}