【LeetCode】最长的斐波那契子序列的长度Java题解

939 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

题目描述

如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的:

n >= 3 对于所有 i + 2 <= n,都有 X_i + X_{i+1} = X_{i+2} 给定一个严格递增的正整数数组形成序列 arr ,找到 arr 中最长的斐波那契式的子序列的长度。如果一个不存在,返回  0 。

(回想一下,子序列是从原序列 arr 中派生出来的,它从 arr 中删掉任意数量的元素(也可以不删),而不改变其余元素的顺序。例如, [3, 5, 8] 是 [3, 4, 5, 6, 7, 8] 的一个子序列)

示例 1:

输入: arr = [1,2,3,4,5,6,7,8]
输出: 5
解释: 最长的斐波那契式子序列为 [1,2,3,5,8] 。

示例 2:

输入: arr = [1,3,7,11,12,14,18]
输出: 3
解释: 最长的斐波那契式子序列有 [1,11,12][3,11,14] 以及 [7,11,18] 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/length-of-longest-fibonacci-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析

  • 今天的算法题目是斐波那契式数组题目,斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)。
  • 理解了斐波那契数列的计算方式之后,题目要求求出最长的斐波那契式的子序列的长度,子序列不需要连续。
  • 首先可以想到的是朴素解法,我们遍历数组的中每一个元素,先确定两个元素,在按照斐波那契数列计算规则,计算下一个数值,如果下一个数值在给出的数组中,则长度至少为3。在查找元素的时候,我们可以使用 hashMap 数据结构,提升查询效率。
  • 在朴素解法中,由于是双重循环遍历,有多余的重复计算。为了提升计算效率,我们可以采用记忆化的方式,缓存之前计算的结果。定义二维数组 memo, 缓存计算结果。memo[i][j] 表示 i, j 位置的斐波那契式数子序列的长度。具体实现代码如下,供参考。

通过代码

class Solution {
    public int lenLongestFibSubseq(int[] arr) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int n = arr.length;
        for (int i = 0; i < n; i++) {
            map.put(arr[i], i);
        }
        int ans = 0;
        int[][] memo = new int[n][n]; 

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int cnt = dfs(map, arr, i, j, memo);
                if (cnt >= 3) {
                    ans = Math.max(cnt, ans);
                }
            }
        }

        return ans;
    }

    private int dfs(Map<Integer, Integer> map, int[] arr, int i, int j, int[][] memo){
        if (memo[i][j] > 0) {
            return memo[i][j];
        }

        memo[i][j] = 2;

        int next = arr[i] + arr[j];
        if (map.containsKey(next)) {
            memo[i][j] = 1 + dfs(map, arr, j, map.get(next), memo);
        }
        return memo[i][j];

    }
}

总结

  • 上述算法的时间复杂度是O(n * n), 空间复杂度是O(n)
  • 坚持算法每日一题,加油!