剑指Offer_#66_构建乘积数组

剑指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)

posted @ 2020-07-29 19:18  Howfar's  阅读(143)  评论(0编辑  收藏  举报