Product of array exclude itself

給一個 array A,求出另一個 array B, B[i] = A[0] .... *A[i-1] * A[i+1] .... *A[n],自己的位置不乘

暴力法就是用 double loop 去算乘積,遇到 i = j 時就不乘,這樣的時間複雜度是 O (n^2)

public List<Long> productExcludeItself(List<Integer> nums) {
    List<Long> results = new ArrayList<>();
    if (nums == null || nums.size() == 0) {
        return results;
    } else if (nums.size() == 1) {
        results.add(1L);
        return results;
    }

    for (int i=0; i<nums.size(); i++) {
        Long product = 1L;
        for (int j=0; j<nums.size(); j++) {
            if (i != j) {
                product = product*Long.valueOf(nums.get(j));
            }
        }
        results.add(product);
    }
    return results;
}

有更好的方法嗎? 有的

我們可以先算出由前往後的除了自己的乘積,然後算出由後往前的除了自己的乘積,

然後在相乘,就可以得出除了自己的乘積

public List<Long> productExcludeItself(List<Integer> nums) {
    List<Long> results = new ArrayList<>();
    if (nums == null || nums.size() == 0) {
        return results;
    }

    Long[] before = new Long[nums.size()];
    Long[] after = new Long[nums.size()];
    before[0] = 1L;

    Long product = before[0];
    for (int i=1; i<nums.size(); i++) {
        before[i] = product*Long.valueOf(nums.get(i-1));
        product = before[i];
    }

    after[nums.size()-1] = 1L;
    product = 1L;
    for (int i=nums.size()-2; i>=0; i--) {
        after[i] = product*Long.valueOf(nums.get(i+1));
        product = after[i];
    }

    for (int i=0; i<nums.size(); i++) {
        results.add(before[i]*after[i]);
    }

    return results;
}

還可對上面進行優化,可以將迴圈降為兩個即可,並且 results 就用 array,回傳時再轉型速度會快很多

迴圈進行優化的步驟為:

首先看一下第一個迴圈我們是把結果放到 before, 再來是把第二迴圈的結果放到 after, 互相的乘積放到 results

那其實可以將 before 的結果直接放到 results, after 的當前乘積(第二迴圈的 after[i]) 就用一個變數紀錄,

然後最後放進 results 時,要跟 results[i] 算乘積

for (int i=nums.size()-2; i>=0; i--) {
    product *= nums.get(i+1);    //由後往前的乘積
    result[i] = results[i] * product;    //由前往後的乘積 * 由後往前的乘積
}

如此可以少了一個迴圈以及 before, after 變數

 public List<Long> productExcludeItself(List<Integer> nums) {
    Long[] results = new Long[nums.size()];
    if (nums == null || nums.size() == 0) {
        return new ArrayList<>(Arrays.asList(results));
    }
    results[0] = 1L;
    Long product = 1L;
    for (int i=1; i<nums.size(); i++) {
        product *= Long.valueOf(nums.get(i-1));
        results[i] = product;
    }
    product = 1L;
    for (int i=nums.size()-2; i>=0; i--) {
        product *= Long.valueOf(nums.get(i+1));
        results[i] = results[i]*product;
    }
    return new ArrayList<>(Arrays.asList(results));
}

邊界條件 result[0] = 1 是為了讓第一個迴圈算乘積時不是 null

results matching ""

    No results matching ""