1027. 最长等差数列
难度:中等
时间:2024/04/21
给你一个整数数组 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 <= 10000 <= nums[i] <= 500
解题思路:
dp[i][d] 表示以数组下标 i 处的元素结尾、公差为 d 的等差数列的最大长度。
动态规划思路:以每个元素作为等差数列终点,计算出该数列长度,选择出最大值返回即可。
在每个位置上,以字典结构保存该位置元素与前面每个位置上元素的差值,与对应该差值的数列长度。
class Solution:
def longestArithSeqLength(self, nums: List[int]) -> int:
minv, maxv = min(nums), max(nums)
diff = maxv - minv
ans = 1
for d in range(-diff, diff + 1):
f = dict()
for num in nums:
if (prev := num - d) in f:
f[num] = max(f.get(num, 0), f[prev] + 1)
ans = max(ans, f[num])
f[num] = max(f.get(num, 0), 1)
return ans
class Solution {
public:
// ---
// 3 6 9 12
// 1 2 3 4
// dp[i][j] = {}
// 动态规划,二维,注意,一维是存不了前向状态的
// 为什么是二维而不是一维:一维dp递推时,前向的 N 可能是不通数列中,不能定唯一数列
// 只有二维,能拿到差值信息
int longestArithSeqLength(vector<int>& nums) {
int len = nums.size();
int res = 0;
vector<vector<int>> dp(len,vector<int>(len,2));
unordered_map<int,int> hash;
for(int i=0;i<len;i++){
for(int j=i+1; j<len; j++){
int diff = nums[j] - nums[i];
int p_v = nums[i]- diff;
if(!hash.count(p_v)) continue;
dp[i][j] = max(dp[i][j], dp[hash[p_v]][i]+1);
res = max(res,dp[i][j]);
}
hash[nums[i]] = i;
for(int j=0;j<len;j++){
// printf("%d\t",dp[i][j]);
}
// printf("\r\n");
}
return max(res,2);
}
};