leetcode:等差數列劃分

題目來源:力扣

題目介紹

如果一個數列至少有三個元素,並且任意兩個相鄰元素之差相同,則稱該數列爲等差數列。
========================================================
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三個子等差數組: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
=======================================================

審題:

對於這道題, 我們首先提供一種易於理解, 但時間複雜度較高的方法.
我們可以計算出所有子序列S[i, j]是否是等差數列, 然後累計其中爲等差數列的個數. 如果我們已知子序列S[i, j]是否是等差數列, 則不能判斷子序列S[i, j+1]是否是等差數列. 因此, 我們可以先計算所有長度爲3的子序列是否是等差數列, 然後一次計算所有長度爲4, …5, n的子序列是否是等差數列.

class Solution {
    public int numberOfArithmeticSlices(int[] A) {
        boolean[][] S = new boolean[A.length][A.length];

        int total = 0;
        //basecase , 判斷長度爲3的數列是否是等差數列
        for(int i = 0; i < A.length-2; i++){
            if(A[i+1]-A[i] == A[i+2]-A[i+1]){
                S[i][i+2] = true;
                total++;
            }
        }

        for(int len = 4; len <= A.length; len++){
            for(int i = 0; i <= A.length-len; i++){
                int j = i + len -1;
                if(S[i][j-1] && A[j]-A[j-1] == A[j-1]-A[j-2]){
                    S[i][j] = true;
                    total++;
                }
                else
                    S[i][j] = false;
            }
        }
        return total;
    }
}

複雜度分析

不難看出, 該方法時間複雜度與空間複雜度均爲O(N2)O(N^2).

實際上, 爲了計算所有等差數列的個數, 我們可以優化上述代碼, 將空間複雜度由O(N2)O(N^2)降爲O(1)O(1). 如果當前A[i, j]爲等差數列, 則我們可以往下判斷A[i, j+1]是否是等差數列, 如果A[i, j]不是等差數列, 則A[i, j+1], …A[i, n]都不是等差數列.

class Solution {
    public int numberOfArithmeticSlices(int[] A) {
        int total = 0;
        for(int i = 0; i < A.length-2; i++){
            for(int len = 2; len < A.length-i; len++){
                if(A[i+len]-A[i+len-1] == A[i+len-1] - A[i+len-2])
                    total++;
                else
                    break;
            }
        }
        return total;
    }
}

動態規劃算法

考慮, 如果我們已知以A[i]結尾的等差數列的個數, 我們能否推導出以A[i+1]結尾的等差數列的個數. 事實上非常容易, 如果A[i+1] - A[i] = A[i]-A[i-1], 那麼所有以A[i+1]結尾的等差數列此時在增加了一個元素A[i+1]後仍然是等差數列, 而A[i-1], A[i], A[i+1]此時也構長一個等差數列, 因此以A[i+1]結尾的等差數列的個數等於以A[i]結尾的等差數列的個數+1. 而如果A[i+1]-A[i] != A[i]-A[i-1], 則以A[i+1]結尾的等差數列個數爲1.
我們不難寫出該動態規劃算法的實現:

class Solution {
    public int numberOfArithmeticSlices(int[] A) {
        //S[j]表示以j結尾的等差序列個數
        //如果A[j+1] - A[j] = A[j] - A[j-1] , S[j+1] = S[j] + 1
        //else S[j+1] = 0;
        if(A.length < 3)
            return 0;
        int total = 0;
        int[] S = new int[A.length];
        if(A[2]-A[1] == A[1]-A[0]){
            S[2] = 1;
            total += S[2];
        }

        for(int i = 3; i < A.length; i++){
            if(A[i] - A[i-1] == A[i-1] - A[i-2]){
                S[i] = S[i-1] + 1;
                total += S[i];
            }
        }
        return total;
    }
}

不難分析發現, 該算法的時間複雜度與空間複雜度均爲O(N)O(N).由於以A[i+1]結尾的等差數列個數只有以A[i]結尾的等差數列個數相關, 因此我們可以考慮進行狀態壓縮, 將空間複雜度降爲O(1)O(1)

class Solution {
    public int numberOfArithmeticSlices(int[] A) {

        if(A.length < 3)
            return 0;
        int total = 0;
        int prev = 0;
        if(A[2]-A[1] == A[1]-A[0]){
            prev = 1;
            total += prev;
        }

        for(int i = 3; i < A.length; i++){
            if(A[i] - A[i-1] == A[i-1] - A[i-2]){
                prev = prev + 1;
                total += prev;
            }
            else
                prev = 0;
        }
        return total;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章