题目:
如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的:
1、n >= 3
2、对于所有 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] 。
提示:
3 <= arr.length <= 1000
1 <= arr[i] < arr[i + 1] <= 10^9
----------------------
思路:
每个斐波那契数列都可以由其最后两位数字精准定位,
例如:定义定位数组为dp[][],对于 arr = [1,2,3,4,5,6,7,8] ,
dp[2][3]表示数列[1,2,3]、dp[3][5]表示数列[1,2,3,5]、dp[5][8]表示数列[1,2,3,5,8];
每个dp元素的值,代表它所定位的数列的长度,例如上面的 dp[2][3]=3 , dp[3][5]=4 , dp[5][8]=5;
则每遍历到一个新的数组元素i,就对dp数组中的新的一列进行赋值
赋值规则:
如果两个前置元素j、k之前并没有形成斐波那契子数列(即dp[j][k]==0),
那就将当前位置存储的斐波那契数列长度dp[k][i]修改为3
如果前置元素j、k之前作为某个斐波那契数列的最后两位元素存在(即dp[j][k]==n,n>=3),
如果这时dp[k][i]的值小于 n+1 就将当前位置存储的斐波那契数列长度dp[k][i]修改为 n+1 ,否则不变
(这一步很容易忽略,动态规划的过程中需要保证当前位置的值是当前对应数组元素i时,能取到的最大值,
否则可能会出现后来得到的较小dp[k][i]值覆盖之前较大dp[k][i]值的情况)
这一步也保证了每个斐波那契数列由其最后两位数字精准定位的正确性!
为了取全局最大的数列长度,在每次刷新dp某元素的值时,都要比较是否大于当前存储的最大值。
本题我一开始是采用暴力三重循环的方式遍历每个节点,结果会出现超时的情况,
所以改用双指针的方式消去一重循环
-----------------------
时间复杂度:O(n²)
空间复杂度:O(n²)
n为数组arr的长度
-----------------
class Solution {
public int lenLongestFibSubseq(int[] arr) {
int len = arr.length;
int res = 0;
int[][] dp = new int[len][len];
for (int i = 2; i < len; i++) {
int j = 0;
int k = i - 1;
while (j < k) {
if (arr[j] + arr[k] == arr[i]) {
if (dp[j][k] == 0) {
dp[k][i] = 3;
}else {
dp[k][i] = Math.max(dp[j][k] + 1, dp[k][i]);
}
res = Math.max(res, dp[k][i]);
j++;
k--;
}else if (arr[j] + arr[k] < arr[i]) {
j++;
}else {
k--;
}
}
}
return res;
}
}
LC