c语言求数列中连续数值组成的等差数列最大长度_最长等差子序列的长度

0ff36b8bd52a3c12142ccee44d1b9815.png

问题描述

给定一个整数数组 A,返回A 中最长等差子序列的长度

输入:[20,1,15,3,10,5,8]
输出:4
解释:最长的等差子序列是 [20,15,10,5]
题目来源:力扣(LeetCode)
链接: https:// leetcode-cn.com/problem s/longest-arithmetic-sequence

问题分析

我们要找出最长的等差子序列,则必须要找出所有的等差子序列,然后比较它们的长度,找出最长的。那么,怎么找,才能保证不重复,不遗漏呢?如果你使用动态规划,做过最大子序列和的问题,那么很容易产生灵感,我们可以依次寻找以数组A[i](0=<i < A.length)结尾的所有等差子序列,并且记录下这些子序列的差值和长度,挂到A[i]的名下,差值和长度都是为了递推。你要说你没做过最大子序列和的问题,那得了,你就把今天这道题的思路记住,它日作为别的题目的灵感,可否?好,话不多说,数据结构已经定义清楚了,接下来就是归纳出递推公式了。

如何由A[i-1]结尾的所有等差子序列,求出以A[i]结尾的所有等差子序列呢?仔细想想,好像以A[i]结尾的等差子序列,并不见得与以A[i-1]结尾的等差子序列,有多大关系呀?事实也确实如此,A[i]的子序列,甚至都不需要A[i-1]的参与,随便举个例子,4,6,9,8,以8结尾的等差子序列4,6,8与以9结尾的等差子序列6,9,一点关系都没有。A[i]与A[i-1]之所以没有明显的关系,是因为这里的等差子序列,并不要求是连续的,而是可以跳跃存在的。事实上,要求出A[i]结尾的等差子序列,则必须一一算出A[i]与A[0...i-1]的差值,分别与以A[0...i-1]结尾的所有等差子序列的差值作比较,若相等,则以这个差值为key,以相等的这个等差子序列的长度+1作为value,挂到A[i]名下;若不等,那就以差值为key,长度2为value丢到A[i]脚下。如果A[i]那里已经有这个key了,那还得比较新的value与原始value的大小,将大的存进去。在递推的过程中,每次更新A[i]的等差子序列的长度时,顺便更新一下我们要的结果,也就是最长等差子序列的长度,循环结束后,返回这个最长等差子序列的长度,即可。

代码实现

    @Test
    public void testAdditiveNumber() {
        int[] A = {9,37,30,50,67,32,47,44,11,15,4,11,3,12,17,18,25,19,21,17,21,23,70,51,61,21,52,25};
        System.out.println("Result: "+new Solution().
                longestArithSeqLength(A));
    }

    class Solution {
        public int longestArithSeqLength(int[] A) {
            if(A == null){
                return 0;
            }else if(A.length < 3){
                return A.length;
            }
            int n = A.length;
            //以A[i]结尾的所有等差数列的差值和长度
            HashMap<Integer, HashMap<Integer, Integer>> diffMap = new HashMap<>();
            for(int i=0; i<n; i++){
                diffMap.put(i, new HashMap<Integer, Integer>());
            }
            diffMap.get(0).put(0, 1);
            diffMap.get(1).put(A[1] - A[0], 2);
            int result = 2;
            for(int i=2; i<n; i++){
                for(int j=i-1; j>=0; j--) {
                    //求a[i]与A[0...i-1]的差值
                    int diff = A[i] - A[j];
                    //以A[j]结尾的所有等差数列中,存在与A[i]-A[j]相等的差值
                    if(diffMap.get(j).containsKey(diff)){
                        //更新以A[i]结尾的等差数列的差值和对应的长度
                        if(diffMap.get(i).get(diff) == null) {
                            diffMap.get(i).put(diff, diffMap.get(j).get(diff) + 1);
                        }else{
                            diffMap.get(i).put(diff, Math.max(diffMap.get(j).get(diff) + 1, diffMap.get(i).get(diff)));
                        }
                    }else{
                        if(diffMap.get(i).get(diff) == null) {
                            diffMap.get(i).put(diff, 2);
                        }
                    }
                    //更新最长等差数列的长度
                    result = Math.max(result, diffMap.get(i).get(diff));
                }
            }
            return result;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值