题目:
如果序列 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] 的一个子序列)
示例 :
输入: arr = [1,2,3,4,5,6,7,8] 输出: 5 解释: 最长的斐波那契式子序列为 [1,2,3,5,8] 。
思路:
动态规划最困难的点在于建立状态转移方程。没想明白。看题解看了好久才明白一点。
dp[ i ][ j ]用来表示以在数组A中以A【i】,A【j】结尾的斐波那契数列的最大长度
也就是 dp[i][j]=Len(......,A[i],A[j])
既然是满足斐波那契数列的那在前面一定有一个A【k】是满足加Ai = Aj的
那么dp【k】【i】加上Aj的长度就等于dp【i】【j】
就是dp【k】【i】 + 1 = dp【i】【j】
复杂度:
时间:双重循环O(n*n)。
空间:dp【】【】二维数组空间O(n^2)。
代码:效率比较拉胯,但是比较容易懂
public int lenLongestFibSubseq(int[] arr) {
int n = arr.length;
//新建一个map存key-value
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i<n;++i){
map.put(arr[i],i);
}
//建立dp数组保存状态
int[][] dp = new int[n][n];
//从0,1开始
int res = 2;
for(int j = 1;j<n;++j){
for(int i = 0;i<j;++i){
//k就是满足arr[i]+arr[k]=arr[j]的,只要能找到k,就有斐波那契数列
int k = map.getOrDefault(arr[j]-arr[i],-1);
dp[i][j] = k>=0 && k<i ? dp[k][i]+ 1:2;
res =Math.max(res,dp[i][j]);
}
}
return res > 2 ? res: 0;
}