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

本文探讨了如何高效计算一个整数数组中等差子序列的数量,并提供了两种算法方案:回溯法和动态规划法。重点介绍了动态规划方法的具体实现过程,通过维护一个二维结构来记录所有可能的等差子序列及其数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值