leetcode446. Arithmetic Slices II - Subsequence

題目要求

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;
    }

在提交之後還有一個耗時特別短的答案,但是這個答案沒看懂,就不多贅述了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章