Skip to content

Latest commit

 

History

History
107 lines (74 loc) · 3.14 KB

1027_最长等差数列.md

File metadata and controls

107 lines (74 loc) · 3.14 KB

题目

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]。

提示:

  • 2 <= nums.length <= 1000
  • 0 <= nums[i] <= 500

代码

class Solution {
    public int longestArithSeqLength(int[] nums) {
        // dp[i][j] 表示公差为j , 等差数列的最长长度
        int max=nums[0],min=max;
        for(int a:nums){
            max = Math.max(a,max);
            min = Math.min(a,min);
        }
        int[][]dp=new int[nums.length+1][(max-min+1)*2];
        for(int[]a:dp){
            Arrays.fill(a,1);
        }
        int res=0;
        for(int i=0;i<nums.length;i++){
            for(int k=0;k<i;k++){
                // 公差
                int val = nums[i]-nums[k] + (max-min);
                dp[i][val]=Math.max(
                    dp[i][val],
                    dp[k][val]+1);
                res=Math.max(res,dp[i][val]);
            }
        }
        return res;
    }
}

思路

看到这种当前状态跟前一种情况有关的题目 , 其实可以先往DP的思路上面靠拢靠拢.

那么一般的, 当我们看到一道DP的题目 , 首先该思考 DP数组怎么定义

比如本题需要 找 等差数列, 并且题目给出的数组都是无序的 (并且序列的顺序我们不能打乱)

这里很容易想到 dp[i] 是需要的, 那么对于另一个关键点 ---- 公差 , 我们再记录一个数组进行统计 ,

也就得出了dp数组的定义 : dp[i][j] 表示 下标为 i 的元素 , 公差为j时候 , 等差数列的最长长度

接着是初始化 , 对于任何一个元素 , 都可以成为一个长度为1 的等差数列, 因此 我们初始化DP数组的所有元素为1 ,

这个时候需要注意题目给出的数据范围 : 0 <= nums[i] <= 500

那么本题公差的范围就是 [-500,500] , 这里也可以先统计一下 最大值和最小值来 进一步节约内存空间

在遍历每一个元素的时候我们统计 当前元素 与 之前的元素可以构成的等差数列的长度

int val = nums[i]-nums[k] + (max-min); dp[i][val]=Math.max( dp[i][val], dp[k][val]+1); res=Math.max(res,dp[i][val]);

这里注意 , 由于 数组的索引是没有负数的, 因此我们定义两倍的 长度 , 在每次计算索引的时候 加上 最大公差的偏移量即可

在计算的过程中维护 res 来统计 最长的等差数列的长度即可