题目描述

给定一个数组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];)

解法一:暴力法

由于 B[i]=A[0] A[1] ... A[i-1] A[i+1] ... A[n-1],乘积的结果不用将 A[i] 的值计算上就行了,暴力法用双重循环就能解决,但是时间复杂度会很高,不推荐这种解法。

public int[] multiply(int[] A) {
        if (A == null || A.length == 0) {
            return null;
        }
        int[] res = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            res[i] = 1;
            for (int j = 0; j < A.length; j++) {
                if (i != j) {
                    res[i] *= A[j];
                }
            }
        }
        return res;
    }

解法二:动态规划

构建乘积数组_第1张图片
根据上面这个图,将 B[i] 的值分为两部分,再将这两部分再乘积即可。以 i 为界限(图中灰色的部分),分为左右两部分。
以 B[2] 为例:
左边 B[2] = A[0] A[1];
右边 B[2] = A[3] ... A[n-2] A[n-1];
最后的结果 = 左边 B[2] 乘以 右边 B[2]。
以 B[3] 为例:
左边 B[3] = A[0] A[1] A[2];
右边 B[3] = A[4] ... A[n-2] A[n-1];
最后的结果 = 左边 B[3] 乘以 右边 B[3]。
以 B[4] 为例:
左边 B[4] = A[0] A[1] A[2] A[3];
右边 B[4] = A[5] ... A[n-2] A[n-1];
最后的结果 = 左边 B[4] 乘以 右边 B[4]。
.
从以上来看,我们会发现一些规律:
在 B[2] 的基础上,我们可以将左边的 B[3] 写成这样:左边 B[3] = B[2] A[2];
在 B[4] 的基础上,我们可以将右边的 B[3] 写成这样:右边 B[3] = A[4] B[4]。
代码实现:

public int[] multiply(int[] A) {
        if (A == null || A.length == 0) {
            return null;
        }
        //左边部分
        int[] left = new int[A.length];
        left[0] = 1;
        for (int i = 1; i < A.length; i++) {
            left[i] = A[i - 1] * left[i - 1];
        }
        //右边部分
        int[] right = new int[A.length];
        right[A.length - 1] = 1;
        for (int i = A.length - 1; i > 0; i--) {
            right[i - 1] = right[i] * A[i];
        }
        //计算总乘积,即将左右两部分相乘
        int[] res = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            res[i] = left[i] * right[i];
        }
        return res;
    }