leetcode413 Arithmetic Slices

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kevinjqy/article/details/69668982

题目

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;
    }
阅读更多

没有更多推荐了,返回首页