1.题目描述
给你一个整数数组
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
2.解题思路
看到提示中的数据范围,可以想到使用二维的dp数组遍历所有的子序列并记录之前的状态
其中二维dp数组的含义为:dp[i][d]表示以下标i为结束位置,且以d为公差的最长等差子序列的长度
那么,我们的dp数组要怎么定义呢?
因为nums中每一个数的大小都在[0,500]之间,那么公差d的范围就是[-500,500],所以我们只需要定义一个长度为1001的数组表示所有的公差,为了让公差能够映射到数组下标上,我们会给每个得到的公差d加上500,避免数组下标出现负数
并且dp数组的初始化:先令所有dp[i][d] =1,因为我们可以认为nums中每一个单独的数字都是一个长为1的等差序列
最重要的一步就是递推公式的计算:我们遍历nums他们的每一个结束位置i,对于[0,i)中的每一个下标作为j,那么dp[i][d] = max(dp[j][d]+1,dp[i][d]),这样就能得到以nums[i]为结束位置的最长等差子序列的长度,只需要维护一个maxLength记录全局的最大值即可
3.代码实现
/**
dp数组的含义
dp[i][d]表示以nums[i]为结尾位置,且以d为公差的最长子序列的长度
**/
class Solution {
public int longestArithSeqLength(int[] nums) {
int n = nums.length;
int[][] dp = new int[n][1001];
for (int i = 0; i < n; i++) {
Arrays.fill(dp[i],1);
}
int maxLength = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
int d = nums[i] - nums[j] + 500;
dp[i][d] = Math.max(dp[i][d],dp[j][d] + 1);
maxLength = Math.max(dp[i][d],maxLength);
}
}
return maxLength;
}
}