如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的:
n >= 3
对于所有 i + 2 <= n,都有 X_i + X_{i+1} = X_{i+2}
给定一个严格递增的正整数数组形成序列,找到 A 中最长的斐波那契式的子序列的长度。如果一个不存在,返回 0 。
(回想一下,子序列是从原序列 A 中派生出来的,它从 A 中删掉任意数量的元素(也可以不删),而不改变其余元素的顺序。例如, [3, 5, 8] 是 [3, 4, 5, 6, 7, 8] 的一个子序列)
示例 1:
输入: [1,2,3,4,5,6,7,8]
输出: 5
解释:
最长的斐波那契式子序列为:[1,2,3,5,8] 。
示例 2:
输入: [1,3,7,11,12,14,18]
输出: 3
解释:
最长的斐波那契式子序列有:
[1,11,12],[3,11,14] 以及 [7,11,18] 。
如果直接使用遍历算法的话,时间复杂度大概是O(n^3)这个数量级,而题目要求中给出的数组A的最大长度为1000,如果使用O(n^3)的算法,势必会超时。
考虑如何简化:斐波那契数列有一个性质,即一但前两个数字确定,整个数列即确定的。故我们使用二维数组来存储这一信息, 二维数组map的两个索引分别为该斐波那契数列前两个数在A中的索引,其对应的值为由该数列在整个序列中的最大长度。
我们只要从后往前遍历整个数组,就能使用到map中所储存的信息,具体代码如下:
代码:
class Solution {
public int lenLongestFibSubseq(int[] A) {
int res = 0;
// HashMap<Integer, Integer []> map = new HashMap<Integer, Integer[]>();
int [][] map = new int [A.length][A.length];
map[A.length- 2][A.length -1] = 2;
// List <Integer> list = new ArrayList<>();
// for(int i = 0 ; i < A.length ; i++){
// list.add(A[i]);
// }
for(int j = A.length - 3; j >= 0; j--){
for(int i = j + 1; i <A.length; i++){
int three = A[j] + A[i];
int index = findIndex(i, three , A);
if(index != -1) {
map[j][i] = map[i][index] +1;
res = Math.max(map[j][i], res);
}else{
map[j][i] = 2;
}
}
}
return res < 3 ? 0: res;
}
public int findIndex(int start, int target, int [] A) {
int end = A.length -1;
while(start <= end) {
int mid = (start + end) / 2;
if(A[mid] < target) {
start = mid +1;
}else if(A[mid] > target) {
end = mid - 1;
}else {
return mid;
}
}
return -1;
}
}