目录
题目
如果序列 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:
输入: 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/length-of-longest-fibonacci-subsequence
解法一:暴力解法
思路
每个斐波那契式的子序列都依靠两个相邻项来确定下一个预期项。例如,对于 2, 5,我们所期望的子序列必定以 7, 12, 19, 31 等继续。
我们可以使用 Set 结构来快速确定下一项是否在数组 A 中。由于这些项的值以指数形式增长,最大值≤110^9 的斐波那契式的子序列最多有 43 项。
public int lenLongestFibSubseq1(int[] A) {
int N = A.length;
Set<Integer> S = new HashSet();// 使用set来存储便于快速查找
for (int x: A) S.add(x);
int res = 0;
for (int i = 0; i < N; ++i)
for (int j = i+1; j < N; ++j) {
int x = A[j]; // 假设从pair(A[i], A[j]) 开始
int y = A[i] + A[j];// y 代表 A[i]->A[j] 的下一个斐波那契数列的元素
int length = 2;
while (S.contains(y)) { // 继续向后搜索以pair (A[i], A[j])开始的斐波那契数列
// x, y -> y, x+y
int tmp = y;
y += x;
x = tmp;
res = Math.max(res, ++length);
}
}
return res >= 3 ? res : 0;
}
复杂度分析
时间复杂度:O(N^2 log M),其中 N是 A 的长度,M是 A 中的最大值。
空间复杂度:O(N),集合(set)S 使用的空间。
解法二:动态规划
动态规划解题步骤
1. 想清楚原问题与子问题
• 子问题为求解结点 (i, j) 结尾的斐波那契子序列的长度
2. 设计状态
• dp(i,j)结点(i, j)结尾的斐波那契子序列的长度
3. 设计状态转移方程
• if(A[k]+A[i] == A[j]) dp(i, j)=dp(k,i)+1
• 目标值 = max( dp(i,j))
4. 确定边界状态值
• dp(i,j)=2
public int lenLongestFibSubseq(int[] A) {
int N = A.length;
Map<Integer, Integer> index = new HashMap();// 建⽴立值到下标的映射便便于快速查找
for (int i = 0; i < N; ++i)
index.put(A[i], i);
Map<Integer, Integer> longest = new HashMap();
int ans = 0;
for (int k = 0; k < N; ++k)
for (int j = 0; j < k; ++j) {
int i = index.getOrDefault(A[k] - A[j], -1);
if (i >= 0 && i < j) {
// 把(i, j) 对应的位置编码成 (i * N + j),这样就可以⽤用⼀一维数组来存储状态
int cand = longest.getOrDefault(i * N + j, 2) + 1; // 利利⽤用状态转移⽅方程来求解
longest.put(j * N + k, cand);// 记录中间状态值,便便于后续求解时调⽤
ans = Math.max(ans, cand);
}
}
return ans >= 3 ? ans : 0;
}
复杂度分析
时间复杂度:O(N^2),其中 N 是 A 的长度。
空间复杂度:O(NlogM),其中 M 是 A 中最大的元素