题目要求:
给定一个数组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]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];)
对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。
思路:
实际上我们仔细看这张图,B[i]其实就是对角线划分的左区域和右区域的一个乘积,那么我们就可以将这两个区域分别遍历,得到B[i]的部分乘积值。
我们首先来分析左下区域的B[i]的部分乘积,B[0]为1,B[1]其实就是A[0],B[2]就是B[1] *A[1],...,以此类推,即:
B[0] = 1;
B[1] = B[0] * A[0];
...
B[n-1] = B[n-2] * A[n-2] = 1 * A[0] * A[1] *....*A[n-2]; (注意此时B[n-1]已经完成了计算,那么反过来退右边的三角区域时不用再考虑它了)
接着我们同理倒着分析右边的三角区域:
每一行都要用前面推出来的B[i]来乘以右边剩下的乘积,右边的乘积我们可以像刚刚那样计算,但是不能直接使用B[i]来存值了,因为之前的每一个B[i]的值我们还要用,那么此刻我们就需要一个暂存变量,来存储右边的乘积。
即倒着来,temp = 1;
temp = temp * A[n-1]
B[n-2] = B[n-2] * temp;
分析结束了,我们放上代码:
import java.util.ArrayList;
public class Solution {
// 思路:实际上就是求把对应位置置1后每行的乘积,可以先算下半区,再算上半区
public int[] multiply(int[] A) {
int[] B = new int[A.length];
// 首先计算下三角区
//
B[0] = 1;
for(int i = 1;i < B.length;i++){
B[i] = B[i-1] * A[i-1];// 攒下三角的乘积
}
int temp = 1;
for(int i = B.length-2;i >= 0;i--){
temp *= A[i+1]; // 攒上半区的乘积
B[i] *= temp;
}
return B;
}
}
题目来自:牛客网剑指offer。
答案参考:https://www.nowcoder.com/profile/645151/codeBookDetail?submissionId=1516453
(最开始还是惯性地使用暴力,看了别人的之后对时间复杂度进行了一个优化,希望以后也能有比较好的算法思维呀!加油)
ps:这个方法相较暴力,时间复杂度从O(n^2)降低到了O(2n),但是空间复杂度好像是升高了,难解。