[leetcode] 413. Arithmetic Slices

来源:互联网 发布:mac电脑有什么游戏好玩 编辑:程序博客网 时间:2024/06/05 07:30

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, 97, 7, 7, 73, -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;    }};
原创粉丝点击