1. 程式人生 > >劍指Offer - 構建乘積陣列(Java實現)

劍指Offer - 構建乘積陣列(Java實現)

題目描述:

給定一個數組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每個位置的值就是陣列A中除了同一位置上的那個數,陣列中剩下的數的累積。一開始我想到的思路是先求出A陣列中所有數的累積,然後再除以A[i]即可獲得B[i]的值。但是題幹中明確要求不能使用除法,所以此法作罷。
這時候又很快想到簡單粗暴的暴力遞迴的方法,直接遍歷兩個for迴圈巢狀。時間複雜度為O(N^2)
程式碼實現如下:
1.暴力遞迴

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

顯然暴力遞迴雖然思想簡單,但是時間複雜度過高,所以這肯定不是本題的考察重點。開始時沒想到動態遞迴這種思路,還是看了牛客網後面的大家討論才明白的,將該位置的左右兩邊的乘積分別存入新陣列中,然後對應位置相乘即可。
在這裡插入圖片描述
左邊的值是自上而下的三角,每一層左邊的乘積都等於上一層的乘積再乘以A(i-1)的值,右邊同理。
2.動態遞迴:
程式碼實現如下:

//考察動態規劃的題

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        if(A == null || A.length< 1){
            return A;
        }
        int length = A.length;
        int[] B = new int[length];
        int[] left = new int[length];//記錄左邊的乘積
        int[] right = new int[length];//記錄右邊的乘積
        
        left[0] = right[length-1] = 1;
        
        for(int i = 1 ; i < length ; i++){
            left[i] = left[i-1]*A[i-1];
        }
        for(int i = length-2 ; i>=0 ; i--){
            right[i] = right[i+1]*A[i+1];
        }
        for(int i = 0 ; i<length ; i++){
            B[i] = right[i]*left[i];
        }
       
        return B;
    }
}