最长等差数列的长度(进阶版——允许公差为零且包含负数)
字数 1273 2025-11-23 09:28:50

最长等差数列的长度(进阶版——允许公差为零且包含负数)

让我为您讲解这个线性动态规划问题。

问题描述

给定一个整数数组 nums,返回数组中最长等差数列的子序列长度。等差数列的公差可以是任意整数(包括0和负数),子序列不要求连续。

示例:
输入:nums = [3,6,9,12]
输出:4
解释:整个数组就是公差为3的等差数列

输入:nums = [9,4,7,2,10]
输出:3
解释:最长的等差数列是 [4,7,10],公差为3

解题思路

第一步:理解问题本质

这是一个二维动态规划问题,我们需要记录以每个位置结尾、以特定公差结尾的最长等差数列长度。

第二步:状态定义

定义 dp[i][d] 表示以第 i 个元素结尾,公差为 d 的最长等差数列长度。

但由于公差 d 可能是任意整数,我们使用哈希表来存储:
dp[i] 是一个哈希表,键是公差 d,值是以 nums[i] 结尾、公差为 d 的最长等差数列长度。

第三步:状态转移方程

对于每个位置 i,我们遍历所有 j < i:

  • 计算公差 d = nums[i] - nums[j]
  • 如果 dp[j] 中存在公差 d,则 dp[i][d] = dp[j][d] + 1
  • 否则 dp[i][d] = 2(至少包含 nums[j] 和 nums[i] 两个元素)

第四步:算法实现

def longestArithSeqLength(nums):
    n = len(nums)
    if n <= 2:
        return n
    
    # dp[i] 是一个字典,存储以nums[i]结尾,不同公差的最长序列长度
    dp = [dict() for _ in range(n)]
    max_length = 2  # 至少有两个元素
    
    for i in range(n):
        for j in range(i):
            diff = nums[i] - nums[j]
            
            # 如果j位置已经有这个公差的序列,就在其基础上加1
            if diff in dp[j]:
                dp[i][diff] = dp[j][diff] + 1
            else:
                # 否则,从j和i开始一个新的等差数列
                dp[i][diff] = 2
            
            max_length = max(max_length, dp[i][diff])
    
    return max_length

第五步:详细步骤分析

让我们用 nums = [3,6,9,12] 来逐步分析:

i=0: dp[0] = {} (第一个元素没有前驱)

i=1: 比较 nums[1]=6 与前面的元素

  • j=0: diff = 6-3 = 3
  • dp[1][3] = 2

i=2: 比较 nums[2]=9 与前面的元素

  • j=0: diff = 9-3 = 6, dp[2][6] = 2
  • j=1: diff = 9-6 = 3, dp[2][3] = dp[1][3] + 1 = 3

i=3: 比较 nums[3]=12 与前面的元素

  • j=0: diff = 12-3 = 9, dp[3][9] = 2
  • j=1: diff = 12-6 = 6, dp[3][6] = dp[2][6] + 1 = 3
  • j=2: diff = 12-9 = 3, dp[3][3] = dp[2][3] + 1 = 4

最终得到最长等差数列长度为4。

第六步:复杂度分析

  • 时间复杂度:O(n²),需要两层循环遍历所有元素对
  • 空间复杂度:O(n²),最坏情况下每个位置可能存储O(n)个不同的公差

第七步:优化考虑

虽然理论上最坏情况空间复杂度是O(n²),但在实际应用中,由于整数范围通常有限,实际使用的空间会小很多。

这个解法能够正确处理:

  • 公差为0的情况(所有相同元素)
  • 公差为负数的情况
  • 不连续的子序列
  • 重复元素的情况

这个问题的关键在于理解等差数列的性质,以及如何通过动态规划来记录不同公差下的序列长度。

最长等差数列的长度(进阶版——允许公差为零且包含负数) 让我为您讲解这个线性动态规划问题。 问题描述 给定一个整数数组 nums,返回数组中最长等差数列的子序列长度。等差数列的公差可以是任意整数(包括0和负数),子序列不要求连续。 示例: 输入:nums = [ 3,6,9,12 ] 输出:4 解释:整个数组就是公差为3的等差数列 输入:nums = [ 9,4,7,2,10 ] 输出:3 解释:最长的等差数列是 [ 4,7,10 ],公差为3 解题思路 第一步:理解问题本质 这是一个二维动态规划问题,我们需要记录以每个位置结尾、以特定公差结尾的最长等差数列长度。 第二步:状态定义 定义 dp[ i][ d ] 表示以第 i 个元素结尾,公差为 d 的最长等差数列长度。 但由于公差 d 可能是任意整数,我们使用哈希表来存储: dp[ i] 是一个哈希表,键是公差 d,值是以 nums[ i ] 结尾、公差为 d 的最长等差数列长度。 第三步:状态转移方程 对于每个位置 i,我们遍历所有 j < i: 计算公差 d = nums[ i] - nums[ j ] 如果 dp[ j] 中存在公差 d,则 dp[ i][ d] = dp[ j][ d ] + 1 否则 dp[ i][ d] = 2(至少包含 nums[ j] 和 nums[ i ] 两个元素) 第四步:算法实现 第五步:详细步骤分析 让我们用 nums = [ 3,6,9,12 ] 来逐步分析: i=0: dp[ 0 ] = {} (第一个元素没有前驱) i=1: 比较 nums[ 1 ]=6 与前面的元素 j=0: diff = 6-3 = 3 dp[ 1][ 3 ] = 2 i=2: 比较 nums[ 2 ]=9 与前面的元素 j=0: diff = 9-3 = 6, dp[ 2][ 6 ] = 2 j=1: diff = 9-6 = 3, dp[ 2][ 3] = dp[ 1][ 3 ] + 1 = 3 i=3: 比较 nums[ 3 ]=12 与前面的元素 j=0: diff = 12-3 = 9, dp[ 3][ 9 ] = 2 j=1: diff = 12-6 = 6, dp[ 3][ 6] = dp[ 2][ 6 ] + 1 = 3 j=2: diff = 12-9 = 3, dp[ 3][ 3] = dp[ 2][ 3 ] + 1 = 4 最终得到最长等差数列长度为4。 第六步:复杂度分析 时间复杂度:O(n²),需要两层循环遍历所有元素对 空间复杂度:O(n²),最坏情况下每个位置可能存储O(n)个不同的公差 第七步:优化考虑 虽然理论上最坏情况空间复杂度是O(n²),但在实际应用中,由于整数范围通常有限,实际使用的空间会小很多。 这个解法能够正确处理: 公差为0的情况(所有相同元素) 公差为负数的情况 不连续的子序列 重复元素的情况 这个问题的关键在于理解等差数列的性质,以及如何通过动态规划来记录不同公差下的序列长度。