1027 最长等差数列(动态规划)

1. 问题描述:

给定一个整数数组 A,返回 A 中最长等差子序列的长度。
回想一下,A 的子序列是列表 A[i_1], A[i_2], ..., A[i_k] 其中 0 <= i_1 < i_2 < ... < i_k <= A.length - 1。并且如果 B[i+1] - B[i]( 0 <= i < B.length - 1) 的值都相同,那么序列 B 是等差的。

示例 1:

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

示例 2:

输入:[9,4,7,2,10]
输出:3
解释:
最长的等差子序列是 [4,7,10]。

示例 3:

输入:[20,1,15,3,10,5,8]
输出:4
解释:
最长的等差子序列是 [20,15,10,5]。

提示:

  1. 2 <= A.length <= 2000
  2. 0 <= A[i] <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-arithmetic-subsequence

2. 思路分析:

① 一开始根据题目的描述以及数据规模感觉应该使用动态规划解决(一开始的时候也有想到递归但是发现发现数据规模太大了肯定是解决不了的而且处理的细节也很复杂),所以比较好的思路是使用动态规划去解决,动态规划可以根据之前的子状态来递推出当前状态对应的dp数组的值,而且最关键的是状态的转移(状态转移方程的编写),因为是需要利用到上一个状态,所以分析题目可以知道我们比较容易想到的是以当前的位置对应的A[i]数字结尾的最长等差序列的长度,以....为结尾主要是为了能够在前面状态的基础上去尝试当前[0:i]的位置对应的等差序列的基础上添加上这个数字形成更长的等差序列,这样就就可以递推出现在的状态的dp数组的值,所以只使用一维的dp数组看上去是不够的,因为我们还需要维护一个0到当前位置结束的公差,这样才可以根据当前位置的公差来更新对应的等差序列的长度,所以应该使用二维的dp数组来实现,dp[i][j]表示的意思是从0到当前的位置i结束的最长等差序列的长度(i表示当前的位置,j表示0:i这些位置的公差)

② 这样我们就可以根据之前的状态递推出当前的状态,此外还需要注意的一点是公差有可能是负数所以我们需要当公差为负数的时候再加上1000(两个数字的最大差值为1000,所以加上1000就可以保证公差是大于等于0的),对于这一类关于数组的动态规划相关的题目,很多dp数组的含义都是以当前数字结尾...的含义(所以我们在做这一类问题的时候首先想到的应该dp数组的含义应该是这个),这也比较容易理解,因为我们需要在前面的状态递推出当前的状态,所以我们到达当前状态的时候肯定是需要知道之前的状态对应的dp数组的值,所以以当前的数字结尾就顺理成章了

3. 代码如下:

from typing import List


class Solution:
    def longestArithSeqLength(self, A: List[int]) -> int:
        dp = [[0] * 1000 for i in range(1000)]
        res = 0
        for i in range(1, len(A)):
            for j in range(i):
                # 根据上一个状态进行递推: 因为公差可能是负数所以加上两个数字的最大差值
                cha = A[i] - A[j] if A[i] - A[j] >= 0 else A[i] - A[j] + 1000
                dp[i][cha] = dp[j][cha] + 1
                res = max(res, dp[i][cha])
        return res + 1

 

你可能感兴趣的:(力扣,动态规划)