LeetCode#413 Arithmetic Slices题解(C++版)

题干

这里写图片描述

原题网址:
https://leetcode.com/problems/arithmetic-slices/description/

题干解析

给你一个数列,要你算出他有多少个等差子序列(等差子序列的长度应该大于等于3)。

知识点

动态规划

难度

中等

解题思路

本题可用动态规划求解,思路有点类似于动态规划的经典题目之求回文子串个数(注意,因为本题要求的是连续的,所以是子串不是子序列),如果熟悉求回文子串的话,修改一下就可以解本道题了。
首先用指针进行动态申请内存,生成一个二维的标志子序列是否为等差的表,行号表示这个子序列的第一个数字在原vector里面的下标,而“列号+i”表示子序列最后一个数字在原vector里面的值。注意这里,我不是直接用列号表示子序列最后一个数字的下标,而是用列号+i,比如:第i行的列号为0的数字,代表着以第i个数字为起始,以第0+i个,也就是第i个数字为截止的长度为1的子序列;第i行的列号为1的数字,代表着以第i个数字为起始,以第i+1个数字为截止的长度为2的子序列。之所以这样做,是因为要节省空间。倘若我直接用列号表示子序列最后一个数字在原序列中的下标的话,我们知道最后一个数字的下标肯定大于等于第一个数字下标,那么那些列号小于行号的就相当于浪费掉了,浪费了将近一半的空间,而且博主亲测这样交上去的话会超出题目的内存限制=。=通过遍历,计算出各个子序列是否为等差,在写代码时这里要注意避免重复计算,其他的就没有什么太大的问题。具体代码如下。

代码

int** is_or_not;  // 标志数列是否为等差的
class Solution {
public:
    void is_slices(vector<int>& A, int i, int j) { // 计算A中的第i个到第j+i个数组成的数列是否为等差序列
        if (j < 2) {  // 如果长度小于3,使其为真
            is_or_not[i][j] = 1;
            return;
        }
        if (is_or_not[i][j] != -1) {  // 如果之前已经计算过了,不再重复计算
            return;
        } else {
            if (is_or_not[i + 1][j - 1] == -1) {  // 如果该序列去掉头尾数字的子序列没有计算过,先计算一下
                is_slices(A, i + 1, j - 1);
            }
            if (is_or_not[i + 1][j - 1] == 0) {  // 如果他的子序列不是等差的,那么他也不是等差的
                is_or_not[i][j] = 0;
            } else if (is_or_not[i + 1][j - 1] == 1) { //如果他的子序列是等差的
                if ((A[i] - A[i + 1]) == (A[i + 1] - A[i + 2]) && (A[j + i] - A[j + i - 1]) == (A[j + i - 1] - A[j + i - 2])) {  //如果他的头尾数字分别与其内部邻居的差值,等于他的等差子序列公差,则他也是等差的
                    is_or_not[i][j] = 1;
                } else {
                    is_or_not[i][j] = 0;
                }
            }
            return;
        }
    }
    int numberOfArithmeticSlices(vector<int>& A) {
        // 动态申请内存
        is_or_not = new int*[A.size()];
        for (int i = 0; i < A.size(); i++) {
            is_or_not[i] = new int[A.size() - i];  // 因为如果这里长度也为A.size()的话会超出内存限制,所以进行了小处理(减少了内存)
            for (int j = 0; j < A.size() - i; j++) {
                is_or_not[i][j] = -1; // 初始化
            }
        }

        //遍历计算各个子数列是否为等差的
        for (int i = 0; i <A.size(); i++) {
            for (int j = 0; j < A.size() - i; j++) {
                is_slices(A, i, j);
            }
        }

        // 算出等差子序列的个数
        int ans = 0;
        for (int i = 0; i < A.size(); i++) {
            for (int j = 0; j < A.size() - i; j++) {
                if (is_or_not[i][j] == 1 && j >= 2) {
                    ans++;
                }
            }
        }

        // 释放动态申请的内存
        for (int i = 0; i < A.size(); i++) {
            delete is_or_not[i];
        }
        delete is_or_not;
        return ans;  // 返回答案
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值