乐趣区

关于后端:873-最长的斐波那契子序列的长度-经典序列-DP-运用题

题目形容

这是 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 多平台公布

退出移动版