最长的斐波那契子序列的长度
如果序列 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[i] < arr[i + 1] <= 10^9示例 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] 。
dp[i][j]以i,j为结尾的最长斐波那契子序列的长度
下标 k i j 值 a nums[i]=b nums[j]=c dp[k][i]
dp[i] [j]
a = nums[ j ] - nums[ i ]
dp[i][j]的值
- a存在,a<b , dp[k][i] + 1;
- a存在 ,b<a<c ,2
- a不存在 ,2
这道题的优化在于hash,去找后两数之差a的时候,
要去找a的下标,need遍历一遍数组,此时我们可以搞一个哈希表,存放下标的值和下标对应的值。class Solution { public int lenLongestFibSubseq(int[] arr) { Map<Integer,Integer> hash=new HashMap<>();// 优化:元素值+下标,需要通过值去找下标 int n = arr.length; for (int i = 0; i < n; i++) { hash.put(arr[i], i); } int[][] dp = new int[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) dp[i][j] = 2; int ret = 2; for (int j = 2; j < n; j++) { // 固定最后一个数 for (int i = 1; i < j; i++) { // 枚举倒数第二个数 int a = arr[j] - arr[i]; if (a < arr[i] && hash.containsKey(a)) { dp[i][j] = dp[hash.get(a)][i] + 1; ret = Math.max(ret, dp[i][j]); } } } return ret < 3 ? 0 : ret; } } //k i j //a arr[i] arr[j]
最长等差数列
给你一个整数数组
nums
,返回nums
中最长等差子序列的长度。回想一下,
nums
的子序列是一个列表nums[i1], nums[i2], ..., nums[ik]
,且0 <= i1 < i2 < ... < ik <= nums.length - 1
。并且如果seq[i+1] - seq[i]
(0 <= i < seq.length - 1
) 的值都相同,那么序列seq
是等差的。示例 1:
输入:nums = [3,6,9,12] 输出:4 解释: 整个数组是公差为 3 的等差数列。示例 2:
输入:nums = [9,4,7,2,10] 输出:3 解释: 最长的等差子序列是 [4,7,10]。示例 3:
输入:nums = [20,1,15,3,10,5,8] 输出:4 解释: 最长的等差子序列是 [20,15,10,5]。
这道题和那个最长斐波那契子序列的题还是比较相似的;
唯一区别就是判断条件以及这道题并不是严格的,去找a元素可能会有多个;
此时我们选择离i位置最近的a
又是O(N^3),可以怎么优化呢?
下标 k i j 对应的值 a nums[ i ] nums[ j ] **dp[i][j]的值**
- a不存在 2
- a存在&&a<nums[i]即k<i dp[i][j]=1+dp[k][i]
- a存在但是位置不对 2
**关于优化**
- 如何保证a的值离nums[i]最近???
- hash?如何保证同时进行dp和离的最近的k值更新?
- **两种填表顺序:**
- 先固定最后一个数,枚举遍历倒数第二个数;
- 先固定倒数第二个数,枚举遍历第一个数;
优化方法:选择第二种,将i位置填完后,将i值放入哈希表!
class Solution { public int longestArithSeqLength(int[] nums) { int n=nums.length; int[][]dp=new int[n][n]; int ret=2; Map<Integer,Integer> hash=new HashMap<>(); hash.put(nums[0],0); for(int i=0;i<n;i++) for(int j=0;j<n;j++) dp[i][j]=2; for(int i=1;i<n;i++){ for(int j=i+1;j<n;j++){ int a=2*nums[i]-nums[j]; if(hash.containsKey(a)&&hash.get(a)<i){//后面的hash.get(a)<i是肯定满足了 dp[i][j]=1+dp[hash.get(a)][i]; ret=Math.max(dp[i][j],ret); } } hash.put(nums[i],i); } return ret; } }