[leetcode] 413. Arithmetic Slices

Question:

A sequence of number is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same.

For example, these are arithmetic sequence:

1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9

The following sequence is not arithmetic.

1, 1, 2, 5, 7

A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair of integers (P, Q) such that 0 <= P < Q < N.

A slice (P, Q) of array A is called arithmetic if the sequence:
A[P], A[p + 1], …, A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q.

The function should return the number of arithmetic slices in the array A.

Example:

A = [1, 2, 3, 4]

return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself.

Solution:

一開始想到的是用動態規劃,假設用 f(i, j) 表示子串 xi,…,xj 是否合法,很容易得到一個狀態轉移方程:

f(i, j) = ( f(i+1, j) && valid(i, i+2) ) || ( f(i, j-1) && valid(j-2, j) )

即 xi,…,xj 是合法的當且僅當 ( xi+1,…,xj 合法且 xi 能加進去) 或 ( xi,…,xj-1 合法且 xj 能加進去)
初始化要考慮所有長度爲 3 的子串是否合法。

這樣的算法時間複雜度爲O(n²)

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int ret = 0;
        vector<vector<bool>> dp(A.size(), vector<bool>(A.size(), false));
        for (int i = A.size() - 3; i >= 0; i--) {
            if (A[i] - A[i+1] == A[i+1] - A[i+2]) {
                dp[i][i+2] = true;
                ret++;
            }
            for (int j = i + 3; j < A.size(); j++) {
                if ( (dp[i+1][j] && A[i] - A[i+1] == A[i+1] - A[i+2])
                    || (dp[i][j-1] && A[j-2] - A[j-1] == A[j-1] - A[j]) ) {
                    dp[i][j] = true;
                    ret++;
                }
            }
        }
        return ret;
    }
};

Solution 2:

AC後看到別人可以有0ms的算法。
這種方法很巧妙,用變量 cur 不斷記錄當前已出現的連續的長度爲3的合法子串的數量,然後用 sum 記錄所有合法的子串,而這樣就只需直接給 sum 加上 cur 即爲目前爲止出現的所有合法子串的數量。

爲什麼這樣是對的呢,原因如下:
例如, [1, 2, 3, 4, 5] 當遍歷到 5 之前就記錄了連續出現的長度爲3的合法子串數量爲 2 ([1, 2, 3] 和 [2, 3, 4]),當遍歷到 5 發現也是一個長度爲 3 的合法子串,則數量增加到 3,而這個 [3, 4, 5] 是可以和此前出現的所有連續的長度爲 3 的合法子串連接起來形成新的合法子串的,即形成 [1, 2, 3, 4, 5] 和 [2, 3, 4, 5],因此只需把 sum 加上 1 個長度爲 3 的合法子串和 cur-1 個當前合法子串和之前連續合法子串連接起來形成的新的合法子串的個數。

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int len = A.size();
        if (len < 3)
            return 0;
        int sum = 0, cur = 0;
        for (int i = 2; i < len; i++){
            if (A[i]-A[i-1] == A[i-1]-A[i-2]){
                cur ++;
                sum += cur;
            }
            else
                cur = 0;
        }
        return sum;
    }
};
發佈了79 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章