leetcode446-Arithmetic-Slices-II-Subsequence

26次阅读

共计 2175 个字符,预计需要花费 6 分钟才能阅读完成。

题目要求

A sequence of numbers 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 sequences:

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 subsequence slice of that array is any sequence of integers (P0, P1, ..., Pk) such that 0 ≤ P0 < P1 < ... < Pk < N.

A subsequence slice (P0, P1, ..., Pk) of array A is called arithmetic if the sequence A[P0], A[P1], ..., A[Pk-1], A[Pk] is arithmetic. In particular, this means that k ≥ 2.

The function should return the number of arithmetic subsequence slices in the array A.

The input contains N integers. Every integer is in the range of -231 and 231-1 and 0 ≤ N ≤ 1000. The output is guaranteed to be less than 231-1.

 
Example:

Input: [2, 4, 6, 8, 10]

Output: 7

Explanation:
All arithmetic subsequence slices are:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]

从一个无序的整数数组中,找到所有等差子数列的数量。这里需要注意,等差子数列要求从原数组中找出 Pk 个下标的元素,其中P0 < P1 < P2... < Pk,且满足A[P1]-A[P0] = A[P2] - A[P1] ... = A[Pk]-A[Pk-1]

1,3,7,51,3,5是等差子数组,但是 1,3,5,7 不是,因为 5 和 7 的相对顺序变了。

思路和代码

这里主要是对高赞答案的中文翻译,这个答案太牛了,也让我对动态规划类型的题目有了全新的思考方式。可见算法题不再多,在于算法思维的构建啊。

原答案链接

这个博主首先确定了使用子问题的答案构成主问题答案的核心思路,即假设要想知道 [0,n] 的数组中等差子数组的个数,可以通过计算出 [0,n-1] 的子数组中等差子数组的个数。假设将计算 [0,k] 的子数组中的等差子数组的个数声明为 P(k),则需要从 P(n-1)推导出 P(n)的结果。

现在思考一下假如想要求出 P(n),我们需要哪些信息。对于任意 0 <=j<n,我们需要知道以 A[j]作为结尾且间隔为 d =A[n]-A[j]的等差数列的个数。但是 P(j)这个函数只提供了以 A[j]为结尾的所有等差数列的个数,因此只以 P(j)作为推导函数是不够的,需要重新建立基础问题函数。

结合上面的分析,新的函数 P(k, d)记录了以 A[k]为结尾,且等差距离为 d 的等差子数组的数量。则可以推导出如下的递推公式:

P(0, d) = 0 d 为任意非负整数
P(i, d) = P(j, d) + 1 其中 A[i]-A[j]=d && 0<= i < j

P(0,d)的推导很好理解,即对于任意间隔的等差数列,以 A[0]为结尾的等差数列的个数一定为 0。
P(i, d) = P(j, d) + 1也很好理解,即以 A[i]为结尾的等差数列的个数等于以 A[j]为结尾的等差数列的个数。但是这里加一其实是为了解决一个问题,即潜在的等差数列的问题。因为可能存在一种情况,如 1,2,3,则除了1,2,3,4 可以构成等差数列,2,3,4也可以构成一个等差数列。因此 P(i,d)会记录所有潜在的等差数列的个数。

在理清楚思路之后,就开始决定如何在代码层面使用具体的数据结构来进行数据的存取。这里采用长度为 A.length 的 Map 数组来存储以 A[i]为结尾的所有间隔的等差子数组的个数,因此 Map 中的 key 为间隔的长度。代码如下:

    public int numberOfArithmeticSlices(int[] A) {if (A.length < 3) return 0;
        int result = 0;
        Map<Long, Integer>[] maps = new Map[A.length];
        for (int i = 0 ; i < A.length ; i++) {maps[i] = new HashMap<>();
            for (int j = i - 1 ; j >= 0 ; j--) {long diff = (long)A[i] - A[j];
                int c1 = maps[i].getOrDefault(diff, 0);
                int c2 = maps[j].getOrDefault(diff, 0);
                result += c2;
                maps[i].put(diff, c1 + c2 + 1);
            }
        }
        return result;
    }

在提交之后还有一个耗时特别短的答案,但是这个答案没看懂,就不多赘述了。

正文完
 0