[LeetCode] 873. Length of Longest Fibonacci Subsequence 最長的斐波那契序列長度



A sequence X_1, X_2, ..., X_n is fibonacci-like if:html

  • n >= 3
  • X_i + X_{i+1} = X_{i+2} for all i + 2 <= n

Given a strictly increasing array A of positive integers forming a sequence, find the length of the longest fibonacci-like subsequence of A.  If one does not exist, return 0.git

(Recall that a subsequence is derived from another sequence A by deleting any number of elements (including none) from A, without changing the order of the remaining elements.  For example, [3, 5, 8] is a subsequence of [3, 4, 5, 6, 7, 8].)github

Example 1:數組

Input: [1,2,3,4,5,6,7,8]
Output: 5
Explanation: The longest subsequence that is fibonacci-like: [1,2,3,5,8].

Example 2:優化

Input: [1,3,7,11,12,14,18]
Output: 3
Explanation:
The longest subsequence that is fibonacci-like:
[1,11,12], [3,11,14] or [7,11,18].

Note:code

  • 3 <= A.length <= 1000
  • 1 <= A[0] < A[1] < ... < A[A.length - 1] <= 10^9
  • (The time limit has been reduced by 50% for submissions in Java, C, and C++.)



這道題給了咱們一個數組,讓找其中最長的斐波那契序列,既然是序列而非子數組,那麼數字就沒必要挨着,可是順序仍是須要保持,題目中說了數組是嚴格遞增的,其實博主認爲這個條件無關緊要的,反正又不能用二分搜索。關於斐波那契數列,想必咱們都據說過,簡而言之,除了前兩個數字以外,每一個數字等於前兩個數字之和。舉個生動的例子,大學食堂裏今天的湯是昨天的湯加上前天的湯。哈哈,是否是瞬間記牢了。那麼既然要找斐波那契數列,首先要肯定起始的兩個數字,以後的全部的數字均可以經過將前面兩個數組相加獲得,那麼比較直接暴力的方法,就是遍歷全部的兩個數字的組合,以其爲起始的兩個數字,而後再用個 while 循環,不斷檢測兩個數字之和是否存在,那麼爲了快速查找,要使用一個 HashSet 先把原數組中全部的數字存入,這樣就能夠進行常數級時間查找了,每找到一個,cnt 自增1(其初始化爲2),而後用 cnt 來更新結果 res 便可。最後須要注意的一點是,若 res 小於3的時候,要返回0,由於斐波那契數列的最低消費是3個,參見代碼以下:orm



解法一:htm

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& A) {
        int res = 0, n = A.size();
        unordered_set<int> st(A.begin(), A.end());
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                int a = A[i], b = A[j], cnt = 2;
                while (st.count(a + b)) {
                    b = a + b;
                    a = b - a;
                    ++cnt;
                }
                res = max(res, cnt);
            }
        }
        return (res > 2) ? res : 0;
    }
};



上面的解法存在着一些重複計算,由於當選定的兩個起始數字爲以前的某個斐波那契數列中的兩個數字時,後面的全部狀況在以前其實就已經計算過了,沒有必要再次計算。因此可使用動態規劃 Dynamic Programming 來優化一下時間複雜度,這道題的 DP 定義式也是難點之一,通常來講,對於子數組子序列的問題,咱們都會使用一個二維的 dp 數組,其中 dp[i][j] 表示範圍 [i, j] 內的極值,可是在這道題,這種定義方式絕對夠你喝兩壺,基本沒法寫出狀態轉移方程,由於這道題有隱藏信息 Hidden Information,就算你知道了子區間 [i, j] 內的最長斐波那契數列的長度,仍是沒法更新其餘區間,由於沒有考慮隱藏信息。再回過頭來看一下斐波那契數列的定義,從第三個數開始,每一個數都是前兩個數之和,因此若想增長數列的長度,這個條件必定要一直保持,好比對於數組 [1, 2, 3, 4, 7],在子序列 [1, 2, 3] 中以3結尾的斐氏數列長度爲3,雖然 [3, 4, 7] 也能夠組成斐氏數列,可是以7結尾的斐氏數列長度更新的時候不能用以3結尾的斐氏數列長度的信息,由於 [1, 2, 3, 4, 7] 不是一個正確的斐氏數列,雖然 1+2=3, 3+4=7,可是 2+3!=4。因此每次只能增長一個長度,並且必需要知道前兩個數字,正確的 dp[i][j] 應該是表示以 A[i] 和 A[j] 結尾的斐氏數列的長度,很特別吧,以前好像都沒這麼搞過。blog

接下來看該怎麼更新 dp 數組,咱們仍是要肯定兩個數字,跟以前的解法不一樣的是,先肯定一個數字,而後遍歷以前比其小的全部數字,這樣 A[i] 和 A[j] 兩個數字肯定了,此時要找一個比 A[i] 和 A[j] 都小的數,即 A[i]-A[j],若這個數字存在的話,說明斐氏數列存在,由於 [A[i]-A[j], A[j], A[i]] 是知足斐氏數列要求的。這樣狀態轉移就有了,dp[j][i] = dp[indexOf(A[i]-A[j])][j] + 1,可能看的比較暈,但其實就是 A[i] 加到了以 A[j] 和 A[i]-A[j] 結尾的斐氏數列的後面,使得長度增長了1。這個更新方式感受跟以前那道 Coin Change 有着殊途同歸之妙。不過前提是 A[i]-A[j] 必需要在原數組中存在,並且還須要知道某個數字在原數組中的座標,那麼就用 HashMap 來創建數字跟其座標之間的映射。能夠事先把全部數字都存在 HashMap 中,也能夠在遍歷i的時候創建,由於咱們只關心位置i以前的數字。這樣在算出 A[i]-A[j] 以後,在 HashMap 查找差值是否存在,不存在的話賦值爲 -1。在更新 dp[j][i] 的時候,咱們看 A[i]-A[j] < A[j] 且 k>=0 是否成立,由於 A[i]-A[j] 是斐氏數列中最小的數,且其位置k必需要存在才能更新。不然的話更新爲2。最後仍是要注意,若 res 小於3的時候,要返回0,由於斐波那契數列的最低消費是3個,參見代碼以下:ci



解法二:

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& A) {
        int res = 0, n = A.size();
        unordered_map<int, int> m;
        vector<vector<int>> dp(n, vector<int>(n));
        for (int i = 0; i < n; ++i) {
            m[A[i]] = i;
            for (int j = 0; j < i; ++j) {
                int k = m.count(A[i] - A[j]) ? m[A[i] - A[j]] : -1;
                dp[j][i] = (A[i] - A[j] < A[j] && k >= 0) ? (dp[k][j] + 1) : 2;
                res = max(res, dp[j][i]);
            }
        }
        return (res > 2) ? res : 0;
    }
};



Github 同步地址:

https://github.com/grandyang/leetcode/issues/873



相似題目:

Split Array into Fibonacci Sequence

Fibonacci Number

Coin Change



參考資料:

https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/

https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/discuss/152343/C%2B%2BJavaPython-Check-Pair



LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索