leetcode413 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.
简单来说就是找到一个数组中的等差数列的个数。

解题思路

当我拿到这题的时候,我的第一反应是动态规划,按照DP的思路,建立一个二维数组,第一个下标代表等差数列的起始位置,第二个下标代表数列的结束位置。初始化即检查从每一项开始的前三个是否是等差数列,即0~2,1~3,2~4…….等等是否是等差数列,如果是,则把二维数组的对应位置为1。状态的转换也很简单,如果当前是等差数列且下一个数字与最后一个数的差值等于最后一个数与前一个数的差,就把这个数字加进去。

public int numberOfArithmeticSlices(int[] A) {
        int len = A.length;
        int[][] res = new int[len][len];
        int count = 0;
        //完成记录数组的初始化
        for (int i = 0; i <= len - 3; i++) {
            if (A[i + 1] - A[i] == A[i + 2] - A[i + 1]) {
                res[i][i + 2] = 1;
                count++;
            }
        }
        for (int start = 0; start <= len - 3; start++) {
            for (int end = start + 2; end < len - 1; end++) {
                //状态的转化
                if (res[start][end] == 1 && A[end + 1] - A[end] == A[end] - A[end - 1]) {
                    res[start][end + 1] = 1;
                    count++;
                } else
                    break;
            }
        }
        return count;
    }

很可惜,虽然这样可以通过所有测试用例,但是空间复杂度过高,不满足要求。既然有问题,那就继续改~
我们又想到题目并没有要求得到具体的哪一段是等差数列,那我们只需要得到各个等差数列的长度即可。举个栗子:

假如有一段等差数列是 1,2,3,4,5,6,7
那么这段等差数列中可以构成的子等差数列是:
长度为3: 123,234,345,456,567
长度为4: 1234,2345,3456,4567
长度为5: 12345,23456,34567
长度为6: 123456,234567
长度为7: 1234567

由等差数列求和公式可得:假设等差数列长度为len,那子等差数列个数为 (len-1)(len-2)/2
那这样就很简单了,我们只需从前往后遍历数组,在遍历的过程中更新start与end,并且在一个等差数列结束时把长度加入记录即可。

public int numberOfArithmeticSlices1(int[] A) {
        int len = A.length;
        if (len <= 2) return 0;
        int start = 0;
        int end = 1;
        ArrayList<Integer> count = new ArrayList<>();
        for (int i = 2; i < len; i++) {
            //如果下一个元素满足等差数列的条件
            if (A[i] - A[end] == A[end] - A[end - 1]) {
                end++;
                if(i==len-1)
                    count.add(end-start+1);
            } else {
                //如果不满足,重置start与end,同时记录上一个满足的数列的长度
                if (end - start + 1 >= 3)
                    count.add(end - start + 1);
                start = end;
                end = i;
            }
        }
        int sum = 0;
        for (int i : count) {
            sum += ((i - 1) * (i - 2) / 2);
        }
        return sum;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值