[Leetcode] 446. Arithmetic Slices II - Subsequence 解题报告

题目

A sequence of numbers 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 sequences:

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 subsequence slice of that array is any sequence of integers (P0, P1, ..., Pk) such that 0 ≤ P0 < P1 < ... < Pk < N.

subsequence slice (P0, P1, ..., Pk) of array A is called arithmetic if the sequence A[P0], A[P1], ..., A[Pk-1], A[Pk] is arithmetic. In particular, this means that k ≥ 2.

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

The input contains N integers. Every integer is in the range of -231 and 231-1 and 0 ≤ N ≤ 1000. The output is guaranteed to be less than 231-1.

思路

1、回溯法:我开始自然而然地想到了回溯法,也就是每个元素我们试着将它加入等差数列中,看看是否符合要求,然后再将它取出来。最终统计出符合条件的等差数列的个数。然而却无法通过大数据测试,因为对于[1,1,1,1,1,1,1,1,1,1,1,1]这样的测试用例,回溯法会涉及到大量的重复计算。

2、动态规划:定义dp[index][diff]表示以A[index]结尾,等差值为diff的序列的个数,那么状态转移方程为dp[index][diff] = sum(dp[i][diff] + 1),其中0 <= i <= index - 1。注意sum内部+1是由于包含了A[index]本身。在实现中,由于以A[index]结尾的序列的diff个数可能是稀疏的, 所以我们采用vector<unordered_map<int,int>> 这种数据结构来表示dp。这种算法的时间复杂度是O(n^2),可以顺利通过大数据测试。

代码

1、回溯法:

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        vector<int> line;
        int count = 0;
        DFS(A, 0, line, count);
        return count;
    }
private:
    void DFS(vector<int> &A, int index, vector<int> &line, int &count) {
        if (index == A.size()) {
            if (line.size() >= 3) {
                ++count;
            }
            return;
        }
        // include A[index]
        if (line.size() < 2) {
            // include A[index]
            line.push_back(A[index]);
            DFS(A, index + 1, line, count);
            line.pop_back();
        }
        else {                      // line.size() >= 2
            // A[index] can be included
            int size = line.size();
            long long diff1 = static_cast<long long>(A[index]) - line[size - 1];
            long long diff2 = static_cast<long long>(line[size - 1]) - line[size - 2];
            if (diff1 == diff2) {
                line.push_back(A[index]);
                DFS(A, index + 1, line, count);
                line.pop_back();
            }
            
        }
        // do not include A[index]
        DFS(A, index + 1, line, count);
    }
};

2、动态规划:

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        if(A.empty()) {
            return 0;
        }
        vector<unordered_map<int,int>> dp(A.size());    //[index, [difference, count]]
        int res = 0;
        for(int i = 0; i < A.size(); ++i) {
            for(int j = 0; j < i; ++j) {
                if((long)A[i] - (long)A[j] > INT_MAX || (long)A[i] - (long)A[j] < INT_MIN) {
                    continue;
                }
                int dif = A[i] - A[j];
                dp[i][dif] += 1;
                if(dp[j].find(dif) != dp[j].end()) {
                    dp[i][dif] += dp[j][dif];
                    res += dp[j][dif];
                }
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值