1. 程式人生 > >LeetCode446. Arithmetic Slices II - Subsequence

LeetCode446. Arithmetic Slices II - Subsequence

原來 hat win ofa leetcode sting nsis plan end

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]

分析

又是一個光題目就得看半天的算法題,前面可以直接無視,直接看它給出的例子就知道這題到底要求什麽了。看了下解答,方法是利用dp。

最少需要記住兩個參數,序列的第一個或者最後一個元素,以及這個序列中的公共差。

f[i][d] denotes the number of arithmetic subsequences that ends with A[i]

and its common difference is d.

下一步是尋找狀態轉移表達式已建立子問題之間的橋梁。試想如果我們現在想要把一個新元素A[i]插入到一個現有的arithmetic sequence中來形成一個新的arithmetic sequence,那麽只有在A[i]和原來的sequence中最後一個元素的差等於其公共差的情況下才能形成新的arithmetic sequence。

技術分享圖片

這裏比較難理解的便是 T(i, d) = summation of (1 + T(j, d)) as long as 0 <= j < i && d == A[i] - A[j]. 這個式子,還是用個例子來說明比較好,如果當前的 j 是 3,公差是1的話 :

1,2,3,4

2,3,4

兩個可能。3,4因為元素個數少於3個所以不構成arithmetic sequence,現在我們將A[i]=A[5]=5加入以構成新的arithmetic sequence,

1,2,3,4,5

2,3,4,5

3,4,5

多了一個,並不是完全等於之前的T(j, d)。

技術分享圖片

dp的特性,子問題之間有重復,和分治不同。

代碼

public int numberOfArithmeticSlices(int[] A) {
    int res = 0;
    Map<Integer, Integer>[] map = new Map[A.length];
        
    for (int i = 0; i < A.length; i++) {
        map[i] = new HashMap<>(i);
            
        for (int j = 0; j < i; j++) {
            long diff = (long)A[i] - A[j];
            if (diff <= Integer.MIN_VALUE || diff > Integer.MAX_VALUE) continue;
                
            int d = (int)diff;
            int c1 = map[i].getOrDefault(d, 0);
            int c2 = map[j].getOrDefault(d, 0);
            res += c2;
            map[i].put(d, c1 + c2 + 1);
        }
    }
        
    return res;
}

map數組用來存儲中間計算結果T(i, d),數組的index對應i,表示arithmetic sequence以A[i]結束;key是公共距離差d,value是arithmetic sequence的個數,也就是T(i, d)。也就說用了map數組一下子存儲了三個基本信息,厲害了。

技術分享圖片

這題真的好難。

參考:https://leetcode.com/problems/arithmetic-slices-ii-subsequence/discuss/92822/Detailed-explanation-for-Java-O(n2)-solution

LeetCode446. Arithmetic Slices II - Subsequence