剑指Offer_#66_构建乘积数组
Contents
题目
给定一个数组 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]。不能使用除法。
示例:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
提示:
所有元素乘积之和不会溢出 32 位整数
a.length <= 100000
思路分析
用除法的解法
本题难点在于题目限制不准用除法,如果可以用除法的话,很好解决。
- 计算
A[]
中所有元素乘积product
- 遍历一遍
A[]
数组,B[i] = product / A[i]
不用除法的解法
将每个B[i]
的表达式写出来,就是下面表格的样子。
我们发现可以每一行被1分为左右两个部分,或者说上三角部分和下三角部分。
我们可以分别计算每一行当中1的左边部分,1的右边部分,然后将两部分相乘,就得到对应的B[i]
。
编码技巧: 计算上下三角部分的乘积时,非常容易弄错,最好先在纸上画出上述表格,然后对照着写,不然容易乱。
解答
解答1:较直观的写法
这个代码比较直观,可读性好,但是空间复杂度稍高,借助2个额外的数组。空间复杂度为O(n)。
class Solution {
public int[] constructArr(int[] a) {
int n = a.length;
if(n == 0) return new int[0];
int[] up = new int[n];//上三角部分乘积
int[] down = new int[n];//下三角部分乘积
//上三角从最下边的1开始迭代
up[n - 1] = 1;
//下三角从最上边的1开始迭代
down[0] = 1;
//计算上三角部分,由下到上累乘
for(int i = n - 2;i >= 0;i--){
up[i] = up[i + 1] * a[i + 1];
}
//计算下三角部分,由上到下累乘
for(int i = 1; i <= n - 1;i++){
down[i] = down[i - 1] * a[i - 1];
}
//最后将上下三角部分逐位对应相乘,得到的新数组就是结果B[0...n-1]
for(int i = 0;i <= n - 1;i++){
up[i] *= down[i];
}
return up;
}
}
复杂度分析
时间复杂度: O(n)
空间复杂度: O(n)
解答2:优化空间复杂度
少用了一个数组,可读性稍微差点。因为b
是返回值,所以不算在空间复杂度内。
class Solution {
public int[] constructArr(int[] a) {
if(a.length == 0) return new int[0];
int[] b = new int[a.length];
b[0] = 1;
//将上三角中的数字乘入b[i]
for(int i = 1; i <= b.length - 1;i++){
b[i] = b[i - 1] * a[i - 1];
}
//将下三角中一行的数字相乘,记作tmp,然后乘入b[i]
int tmp = 1;
for(int i = a.length - 2;i >= 0;i--){
tmp *= a[i + 1];
b[i] *= tmp;
}
return b;
}
}
复杂度分析
时间复杂度: O(n)
空间复杂度: O(1)