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[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为结尾的最长斐波那契子序列的长度

下标kij
anums[i]=bnums[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]

最长等差数列 

1027. 最长等差数列

给你一个整数数组 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),可以怎么优化呢?

下标kij
对应的值anums[ 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值更新?
  • **两种填表顺序:**
  1.  先固定最后一个数,枚举遍历倒数第二个数;
  2.  先固定倒数第二个数,枚举遍历第一个数;

优化方法:选择第二种,将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;
    }
}

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sqyaa.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值