共计 1874 个字符,预计需要花费 5 分钟才能阅读完成。
题目形容
这是 LeetCode 上的 873. 最长的斐波那契子序列的长度 ,难度为 中等。
Tag :「序列 DP」、「哈希表」、「动静布局」
如果序列 $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$
序列 DP
定义 $f[i][j]$ 为应用 $arr[i]$ 为斐波那契数列的最初一位,应用 $arr[j]$ 为倒数第二位(即 $arr[i]$ 的前一位)时的最长数列长度。
不失一般性思考 $f[i][j]$ 该如何计算,首先依据斐波那契数列的定义,咱们能够间接算得 $arr[j]$ 前一位的值为 $arr[i] – arr[j]$,而疾速得悉 $arr[i] – arr[j]$ 值的坐标 $t$,能够利用 arr
的严格枯燥递增性质,应用「哈希表」对坐标进行转存,若坐标 $t$ 存在,并且合乎 $t < j$,阐明此时至多凑成了长度为 $3$ 的斐波那契数列,同时联合状态定义,能够应用 $f[t][j]$ 来更新 $f[i][j]$,即有状态转移方程:
$$
f[i][j] = \max(3, f[j][t] + 1)
$$
同时,当咱们「从小到大」枚举 $i$,并且「从大到小」枚举 $j$ 时,咱们能够进行如下的剪枝操作:
- 可行性剪枝:当呈现 $arr[i] – arr[j] >= arr[j]$,阐明即便存在值为 $arr[i] – arr[j]$ 的下标 $t$,依据
arr
枯燥递增性质,也不满足 $t < j < i$ 的要求,且持续枚举更小的 $j$,依然有 $arr[i] – arr[j] >= arr[j]$,仍不非法,间接break
掉以后枚举 $j$ 的搜寻分支; - 最优性剪枝:假如以后最大长度为
ans
,只有当 $j + 2 > ans$,咱们才有必要往下搜寻,$j + 2$ 的含意为以 $arr[j]$ 为斐波那契数列倒数第二个数时的实践最大长度。
代码:
class Solution {public int lenLongestFibSubseq(int[] arr) {
int n = arr.length, ans = 0;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < n; i++) map.put(arr[i], i);
int[][] f = new int[n][n];
for (int i = 0; i < n; i++) {for (int j = i - 1; j >= 0 && j + 2 > ans; j--) {if (arr[i] - arr[j] >= arr[j]) break;
int t = map.getOrDefault(arr[i] - arr[j], -1);
if (t == -1) continue;
f[i][j] = Math.max(3, f[j][t] + 1);
ans = Math.max(ans, f[i][j]);
}
}
return ans;
}
}
- 工夫复杂度:存入哈希表复杂度为 $O(n)$;
DP
过程复杂度为 $O(n^2)$。整体复杂度为 $O(n^2)$ - 空间复杂度:$O(n^2)$
最初
这是咱们「刷穿 LeetCode」系列文章的第 No.873
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。
在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。
为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSou…。
在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。
更多更全更热门的「口试 / 面试」相干材料可拜访排版精美的 合集新基地 🎉🎉
本文由 mdnice 多平台公布