Leetcode——413. 等差数列划分

概述

题目链接

  • 注意:题目要求连续子数组个数至少有3个元素,但是数据只确保>=1,所以可以特殊处理一下

分析

暴力解

枚举所有长度大于 2 的连续子数组,如果是等差数列,给计数器加 1

双指针——滑动窗口法

左指针指向所有包含该元素的符合条件的等差子数组

右指针开始移动,确定等差数组的差值,只有后面一个数字满足该差值,就可以组成一个子数组,结果加1

如果右指针指向的数字不满足之前的差值 或 指向的数组的末尾,则说明包含左指针元素的所有等差子数组已经找完,

于是移动左指针,继续操作

动态规划

不同的dp[i]含义,有不同的动态规划方法

dp[i]:表示[0,i]的元素中,符合条件的结果数

  • dp[i] = dp[i -1] + {加入nums[i]后可以增加的结果数}

dp[i]:表示所有以nums[i]结尾的子数组满足条件的结果数

  • if(nums[i] - nums[i-1] == nums[i-1] - nums[i - 2]),dp[i] = dp[i - 1] + 1

思路

暴力解

  • 如何枚举所有的组合?
    • 两层循环枚举所有连续数组,内层还要一个循环判断是否为等差数列
    • 时间复杂度是 O ( n 3 ) O(n^3) O(n3),代码略

双指针——滑动窗口法

  • 套用模版就行

动态规划

方法1:

  • 关键在于如何确定【加入nums[i]后可以增加的结果数】这一部分的值

  • 我们可以注意到

    1 2 ---> dp[2] = 0
    1 2 3 ---> dp[3] = 1 = dp[2] + 1;
    1 2 3 4 ---> dp[4] = 3 =  dp[3] + 2;
    1 2 3 4 5 ---> dp[5] = 6 = dp[4] + 3;
    1 2 3 4 5 7 ---> dp[6] = 6 = dp[5] + 0;
    

    也就是说,如果是一个连续增加的值,那么没增加一个值,相较于前一个dp,加入num[i]后增加的结果数是递增的;

    但是如果一旦不连续,则增加的值需要清空重新计算

方法2:

  • 直接编写代码就行

代码

双指针——滑动窗口法

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
      	int n = A.size();
        int res = 0;		// 用来保存结果
        for (int i = 0; i < n - 2; i++) {	// i是左指针
            int d = A[i + 1] - A[i];		// 记录如果包含nums[i]的连续子数组需要满足的差值
            for (int j = i + 1; j < N - 1; j++) {		// 右指针开始移动
                if (A[j + 1] - A[j] == d) 	// 只要满足,就增加结果
                    res ++;
                else
                    break;
            }
        }
        return res;
    }
};

动态规划——法1

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        if (nums.size() < 3)    return 0;
        vector<int> dp(nums.size() + 1);
        dp[1] = 0;
        dp[2] = 0;
        int inc = 1;		
        for (int i = 3; i <= nums.size(); ++i) {
            if (nums[i - 1] - nums[i - 2] == nums[i - 2 ] - nums[i - 3]) {
                dp[i] = dp[i - 1] + inc;
                ++inc;      // 关键在于inc
            }
            else {		// 一旦不连续,则inc重新从1开始
                dp[i] = dp[i - 1];
                inc  = 1;
            }
        }
        return dp[nums.size()];
    }
};

动态规划——法2

class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
    int n = nums.size();
    if (n < 3) return 0;
    
    vector<int> dp(n, 0);
    for (int i = 2; i < n; ++i) {
        if (nums[i] - nums[i-1] == nums[i-1] - nums[i-2]) {
            dp[i] = dp[i-1] + 1;
        } 
    }
    return accumulate(dp.begin(), dp.end(), 0);		// 最后要累积所有结果
}
};

这种动态规划思想,有点类似双指针的想法。
只是双指针设定为起始节点,而该动态规划设定为结尾结点

你可能感兴趣的:(LeetCode刷题,c++,刷题,动态规划,滑动窗口)