leetcode
leetcode 2951 ~ 3000
最长的斐波那契子序列的长度

最长的斐波那契子序列的长度

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 468 ms, 内存: 23.6 MB


import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

/**
 * Using Java Streams to solve the problem involves creating maps and performing the same dynamic programming logic
 * but with stream operations. This approach showcases the use of modern Java features.
 */
public class Solution {
    public int lenLongestFibSubseq(int[] arr) {
        int n = arr.length;
        Map<Integer, Integer> index = new HashMap<>();
        IntStream.range(0, n).forEach(i -> index.put(arr[i], i));
        Map<Integer, Integer> longest = new HashMap<>();
        int[] maxLen = {0};

        IntStream.range(0, n).forEach(i ->
            IntStream.range(i + 1, n).forEach(j -> {
                int a = arr[i];
                int b = arr[j];
                int len = 2;
                while (index.containsKey(a + b)) {
                    int c = a + b;
                    a = b;
                    b = c;
                    len++;
                }
                maxLen[0] = Math.max(maxLen[0], len);
            })
        );

        return maxLen[0] >= 3 ? maxLen[0] : 0;
    }
}

解释

方法:

该题解采用了动态规划的方法。首先,利用哈希表maps存储数组中每个元素的索引,以便快速查找。dp[i][j]表示以arr[i]和arr[j]为最后两个元素的斐波那契子序列的最大长度。通过双层循环遍历所有可能的arr[i]和arr[j]组合,对每个组合,计算差值arr[i]-arr[j],并检查该差值是否存在于数组中。如果存在,说明可以形成一个斐波那契子序列,dp表更新为dp[j][k]+1,k是差值对应的索引。循环中还使用一个变量res来维护全局的最长子序列长度。注意,为了避免无效计算,当arr[j]的两倍小于等于arr[i]时,内层循环会提前终止。

时间复杂度:

O(n^2)

空间复杂度:

O(n^2)

代码细节讲解

🦆
为什么在动态规划解法中,dp数组的初始化值是0?在更新dp[i][j]时,直接赋值dp[j][k]+1是否会导致错误的结果?
在动态规划中,dp数组的初始化值通常代表一个基础状态,对于斐波那契序列问题,0表示没有有效的斐波那契序列的初始状态。在更新dp[i][j]时,如果直接赋值为dp[j][k]+1,在没有确认存在一个有效的斐波那契子序列(即至少包含三个数)之前,这种更新可能会导致错误的结果。这是因为dp[j][k]+1可能仅仅是基于一个非斐波那契序列的两个数的错误延伸。因此,我们需要验证当前序列至少能形成一个包含三个数字的斐波那契序列。
🦆
动态规划表中dp[i][j]为什么要取max(dp[j][k]+1, 3)而不是直接dp[j][k]+1?请解释这里为什么要确保最小长度为3。
斐波那契序列定义中,至少包含三个元素,这些元素满足后一个数是前两个数的和。因此,在动态规划更新中,即使通过dp[j][k]+1找到了一个潜在的序列增长方式,我们还需要确保这个更新的序列长度至少为3,这是斐波那契序列的基本要求。如果不这样做,我们可能会错误地将长度小于3的序列计算在内,这不符合斐波那契序列的定义。
🦆
在解法中提到当arr[j]*2 <= arr[i]就终止内循环,这个优化是基于什么逻辑或者数学原理?
这一优化的逻辑基于斐波那契数列的性质:在任何斐波那契序列中,任意两个连续的数a和b(a < b),下一个数c(c = a + b)总是大于b。因此,如果在数组中存在某个元素arr[i],使得arr[j]*2 <= arr[i],则不存在任何数k使得arr[k] + arr[j] = arr[i](因为arr[j] < arr[k]应该成立,但arr[k]至少应该为arr[i] - arr[j],此时arr[j] < arr[i] - arr[j]不成立)。所以,当arr[j]的两倍小于等于arr[i]时,意味着不可能通过当前的j和任何更小的数形成斐波那契序列,提前终止循环可以减少不必要的计算。

相关问题