LeetCode 413. Arithmetic Slices

413. Arithmetic Slices

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, 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 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.

题目内容:
题目给出一个数组,让我们找出这个数组里面元素数量不少于3的子数组,这些子数组构成一个等差数列。

解题思路:
这道题用动态规划(Dynamic Programming)可以解决。一开始我想到一个方法,但是结果提交的时候提示超过了限制的内存。先说一说这个方法。
首先,要确定一个子数组,我们需要确定这个子数组在元素组中的左边界 left 和右边界 right ,我令 arithmetic[i][j] 表示长度为i,从j开始的子数组是否为一个等差数列,对于这样的一个数组,右边界为 k=j+i1 值为1的时候表示是一个等差数列,值为0表示不是一个等差数列,那么,状态转移方程就是

arithmetic[i][j]=arithmetic[i1][j]+(num[k]num[k1]==num[k1]num[k2])?1:0

对于例子,num=[1, 2, 3, 4, 7],可以得到一面这个arithmetic二维数组:
图片名称
这个二维数组中1的个数就是所有等差子数组的个数。可惜这种方法超过了限制的内存大小。代码见下方的方法一。

后来,看到别人的另外一种动态规划的方法,这种方法使用一个数组,假如叫做result来保存以某一位作为最后一个数字的等差数列的个数,例如result[5]表示以原素组中第5个数字作为最后一个数字的等差数列的个数。因为题目要求子数组的个数不少于3,所以result有意义的值应该从result[2]开始,所以先计算result[2],当 i>=3 状态迁移方程为:

result[i]=result[i1]+(num[i]num[i1]==num[i1]num[i2])?1:0

代码见下方的方法二。





方法一代码(超内存):

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        cout << A.size() << endl;
        if (A.size() <= 2) return 0;
        int result = 0;
        int** arithmetic = new int*[A.size() - 2];
        int* diff = new int[A.size() - 1];

        for (int i = 0; i < A.size() - 2; i++) {
            int len = i + 3;
            arithmetic[i] = new int[A.size() - len + 1];
        }
        for (int i = 0; i < A.size() - 1; i++) {
            diff[i] = A[i + 1] - A[i];
        }

        for (int len = 3; len <= A.size();  len++) {
            for (int left = 0; left < A.size() - len + 1; left++) {
                int right = left + len - 1;
                int row = len - 3;
                int col = left;
                if (left + 2 == right) {
                    if (diff[left] == diff[left + 1]) {
                        arithmetic[row][col] = 1;
                        result++;
                    }
                    else {
                        arithmetic[row][col] = 0;
                    }
                }
                else {
                    if (arithmetic[row - 1][col] == 1) {
                        if (diff[right - 2] == diff[right - 1]) {
                            arithmetic[row][col] = 1;
                            result++;
                        }
                        else {
                            arithmetic[row][col] = 0;
                        }
                    }
                    else {
                        arithmetic[row][col] = 0;
                    }
                }
            }
            if (len >= 4) delete[] arithmetic[len - 4];
        }

        delete[] arithmetic;
        delete[] diff;
        return result;
    }

};

方法二代码:

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        if (A.size() <= 2) return 0;
        int total = 0;
        int* result = new int[A.size()];
        result[2] = 0;
        if (A[0] - A[1] == A[1] - A[2]) result[2] = 1;
        total = result[2];
        for (int i = 3; i < A.size(); i++) {
            if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) result[i] = result[i - 1] + 1;
            else result[i] = 0;
            total += result[i];
        }
        return total;
    }

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值