(动态规划)leetcode-873

88 阅读1分钟

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

题目

如果序列 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构成,那么我们怎么考虑动态方程呢?

  • 取dp[x][y] (x<y)表示结尾为 arr[x], arr[y] 所组成的最长斐波那契序列
  • 推出,数组如果存在一个数 arr[z] 满足 arr[x] + arr[y] ,
  • 那么 dp[y][z]=max(dp[x][y]+1,dp[y][z])
  • 而怎么判断这个数arr[z]是否存在,以及这个数所在数组的位置,我们可以采用hashmap
  • key:arr[z]   value: z
  • 对于最长斐波那契序列的长度,我们只要在求出每一个dp[x][y],做比较即可
  • int res = 0 ; res = max(dp[x][y],res)

代码

class Solution {
    public int lenLongestFibSubseq(int[] arr) {
            int len = arr.length;
            if(len<3){
                return 0;
            }
            HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
            int dp[][] = new int[len][len];
            int index = 0 ;
            for(int x :arr){
                map.put(x,index++);
            }
            int max = 0 ;
            for(int i = 0 ; i < len ; i++){
                for(int j = i+1 ; j < len; j++){
                    if(map.containsKey(arr[i]+arr[j])){
                        int x = map.get(arr[i]+arr[j]);
                        dp[j][x]=Math.max(dp[i][j]+1,dp[j][x]);
                       if(max<dp[j][x]){
                           max = dp[j][x];
                       }
                    }
                }
            }
            return max==0?0:max+2;
    }
}