leetcode 873. Length of Longest Fibonacci Subsequence(最长的Fibonacci子序列)

A sequence X1, X2, …, Xn is Fibonacci-like if:

n >= 3
Xi + Xi+1 = Xi+2 for all i + 2 <= n
Given a strictly increasing array arr of positive integers forming a sequence, return the length of the longest Fibonacci-like subsequence of arr. If one does not exist, return 0.

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

Example 1:

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

Constraints:

3 <= arr.length <= 1000
1 <= arr[i] < arr[i + 1] <= 109

求最长的Fibonacci子序列的长度。
Fibonacci子序列是指Xi + Xi+1 = Xi+2 for all i + 2 <= n

思路:
Xi + Xi+1 = Xi+2
知道Xi+2时,还需要知道Xi和Xi+1,也就是说,到Xi+2为止的数组,它的Fb子序列的长度,等于以Xi和Xi+1为结尾的Fb子序列的长度+1。

假如arr[i], arr[j], arr[k]可组成Fb子序列,定义dp[i][j]为 以arr[i]和arr[j]结尾的Fb子序列长度,那么dp[j][k] = dp[i][j] + 1,也就是说,以arr[j], arr[k]为结尾的Fb子序列长度,是在arr[i], arr[j]为结尾的Fb序列长度基础上加1的。

可不断遍历j,在j的右边遍历k,然后找到是否存在i,使arr[i]+arr[j] == arr[k],如果找到,dp[j][k] = dp[i][j]+1
至于如何找arr[i],可事先把(arr[i], i)存入HashMap,在HashMap中找arr[k]-arr[j]即可。

序列是严格递增的,所以arr[i] < arr[j],如果arr[k] - arr[j],也就是arr[i] >= arr[j]时,可剪枝直接跳到下一个j。

最短的Fb子序列长度是3,所以要初始化长度为2,后面在此基础上不断+1。或者初始化为0,在结果上统一+2

    public int lenLongestFibSubseq(int[] arr) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int n = arr.length;       
        int[][] dp = new int[n][n];
        int result = 0;
        
        for(int i = 0; i < n; i++) {
            map.put(arr[i], i);
        }
        
        for(int j = 1; j < n-1; j++) {
            for(int k = j+1; k < n; k++) {
                int ai = arr[k] - arr[j];
                if(ai >= arr[j]) break;
                if(map.containsKey(ai)) {
                    dp[j][k] = dp[map.get(ai)][j] + 1;
                    result = Math.max(result, dp[j][k]);
                }
            }
        }
        return result==0 ? 0 : result+2;
    }

既然序列是严格递增的,已知arr[k],可用双指针来找arr[i]和arr[j],使arr[i]+arr[j]=arr[k],dp方法和上面一样。

    public int lenLongestFibSubseq(int[] arr) {
        int n = arr.length;
        int[][] dp = new int[n][n];
        int result = 0;
        
        for(int i = 2; i < n; i++) {
            int left = 0;
            int right = i - 1;
            while(left < right) {
                int tmpSum = arr[left] + arr[right];
                if(tmpSum > arr[i]) {
                    right --;
                } else if(tmpSum < arr[i]) {
                    left ++;
                } else {
                    dp[right][i] = dp[left][right] + 1;
                    result = Math.max(result, dp[right][i]);
                    left ++;
                    right --;
                }
            }
        }
        
        return result==0 ? 0 : result+2;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值