动态规划动态规划

【DP】1027. Longest Arithmetic Seq

2019-04-30  本文已影响0人  牛奶芝麻

问题描述:

Given an array A of integers, return the length of the longest arithmetic subsequence in A.

Recall that a subsequence of A is a list A[i_1], A[i_2], ..., A[i_k] with 0 <= i_1 < i_2 < ... < i_k <= A.length - 1, and that a sequence B is arithmetic if B[i+1] - B[i] are all the same value (for 0 <= i < B.length - 1).

Example 1:
Input: [3,6,9,12]
Output: 4
Explanation: 
The whole array is an arithmetic sequence with steps of length = 3.
Example 2:
Input: [9,4,7,2,10]
Output: 3
Explanation: 
The longest arithmetic subsequence is [4,7,10].
Example 3:
Input: [20,1,15,3,10,5,8]
Output: 4
Explanation: 
The longest arithmetic subsequence is [20,15,10,5].
Note:
2 <= A.length <= 2000
0 <= A[i] <= 10000

解题思路:

这是一道求最长等差子序列的动态规划题目。问题的关键在于记录每一个元素与之前所有元素的差值次数。
[9,4,7,2,10] 为例,对于数字7,前面的数中,9与它的差值为2,4与它的差值为-3,因此可以考虑用dict {差值: 次数}来记录7。对于数字10,当遍历10前面的数字时,遍历到7,差值是-3,因为-3在7的位置出现过,因此在10的位置处,差值为-3的次数就为2。

因此,我们可以对列表中的每一个数建立一个字典,数据结构为 dp = [dict() for _ in A](注意不要写成 dp = [dict()] * len(A),因为这样在每次修改 dp[i] 时,其他的dict()会同时修改,即这样的初始化字典数组的方法是传引用式的)。

对于 dp[i][j] = k,表示以第 i 个数结尾的子序列,差为 j 时的最长子序列长度为 k。如上述例子,记录以7为结尾的子序列的差值和次数,7对应的字典应该是 {2: 1, -3:1},即 dp[2][2] = 1, dp[2][-3] = 1

对任何差值 x,dp[i][x] = 1 为初始状态。每次循环枚举 j < i,计算 x = A[j] − A[i],如果差值 x 在 dp[j] 元素中出现过,则转移方程为 dp[i][x] = dp[j][x] + 1

最后,返回 dp 中所有 N 个字典中的次数的最大值,+1 就是最后的结果(因为求的是等差子序列的长度,因此结果等于最大差值次数加1)。

时间复杂度为 O(n^2),空间复杂度也为 O(n^2)。

Python3 实现:

class Solution:
    def longestArithSeqLength(self, A):
        dp = [dict() for _ in A]
        maxl = 0
        for i in range(1, len(A)):
            for j in range(0, i):
                sub = A[j] - A[i]
                if sub in dp[j].keys():
                    dp[i][sub] = dp[j][sub] + 1
                else:
                    dp[i][sub] = 1
                maxl = max(maxl, dp[i][sub])
        return maxl + 1

print(Solution().longestArithSeqLength([9,4,7,2,10]))  # 3
print(Solution().longestArithSeqLength([83,20,17,43,52,78])) # 2
上一篇下一篇

猜你喜欢

热点阅读