剑指Offer-53-构建乘积数组

项目地址:https://github.com/SpecialYy/Sword-Means-Offer

题目

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

解析

预备知识

其实就是简单的连乘问题。如果没有除法的限制,此题非常简答。事先求出所有元素的乘积result,然后只需将result除以A的每一项即可得到对应的B中的每一项。但是题目要求了不能使用除法,故而就要想其他思路了。

思路一

我们观察到B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1],式子中没有A[i]项。那么不妨把此式子分开,这样就可以看做A[0]*A[1]*...*A[i-1]的连乘和A[i+1]*...*A[n-1]的连乘。问题转换为连乘后就简单多了,我们只需事先初始化好连乘部分。
比如我们定义左部分连乘为left,右部分连乘为right。那么B[i] = left[i - 1] * right[i + 1]。
其中,left[i - 1]表示0到i - 1项连乘;right[i + 1]表示i + 1到n - 1连乘。
对于连乘我们可以采用简单的动态规划来做,比如:

    left[i] = left[i - 1] * A[i]

    right[i] = right[i + 1] * A[i]

对于B的第0项和第n - 1项要特殊处理。第0项只有右部分连乘,第n - 1项只有左部分连乘。

    /**
     * B[i] = left[i - 1] * right[i + 1]
     * @param A
     * @return
     */
    public static int[] multiply(int[] A) {
        int[] left = new int[A.length];
        int[] right = new int[A.length];
        int[] B = new int[A.length];
        int result = 1;
        //初始化左部分连乘
        for(int i = 0; i < A.length; i++) {
            left[i] = (result *= A[i]);
        }
        result = 1;
        //初始化右部分连乘
        for(int i = A.length - 1; i >= 0; i--) {
            right[i] = (result *= A[i]);
        }
        for(int i = 0; i < A.length; i++) {
            B[i] = i == 0 ? 1 : left[i - 1];
            B[i] *= i == A.length - 1 ? 1 : right[i + 1];
        }
        return B;
    }

思路二

就是对思路一的改进,我们完全可以不用额外申请left,right数组。
思路是先对B中的每一项求出左部分的连乘的值。
然后倒序遍历B中的每一项乘以右部分的连乘的值即可得到最终B中元素值。

    /**
     * 简化版
     * @param A
     * @return
     */
    public static int[] multiply2(int[] A) {
        int[] B = new int[A.length];
        B[0] = 1;
        for(int i = 1; i < A.length; i++) {
            B[i] = B[i - 1] * A[i - 1];
        }
        int result = 1;
        for(int i = A.length - 2; i >= 0; i--) {
            result *= A[i + 1];
            B[i] *= result;
        }
        return B;
    }

总结

整体无法很好的解决的话,就分开搞。

你可能感兴趣的:(不刷题心里难受,剑指Offer)