[LeetCode] 1027. Longest Arithmetic Subsequence

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

Note that:

  • subsequence is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.
  • A sequence seq is arithmetic if seq[i + 1] - seq[i] are all the same value (for 0 <= i < seq.length - 1). 

Example 1:

Input: nums = [3,6,9,12]
Output: 4
Explanation:  The whole array is an arithmetic sequence with steps of length = 3.

Example 2:

Input: nums = [9,4,7,2,10]
Output: 3
Explanation:  The longest arithmetic subsequence is [4,7,10].

Example 3:

Input: nums = [20,1,15,3,10,5,8]
Output: 4
Explanation:  The longest arithmetic subsequence is [20,15,10,5].

Constraints:

  • 2 <= nums.length <= 1000
  • 0 <= nums[i] <= 500

最长等差数列。

给你一个整数数组 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 是等差的。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-arithmetic-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路是动态规划。这道题是300题那种类似LIS的题目的延伸,但是这道题的一个难点在于你不光是要找升序或者降序的子数组,统计长度,同时你需要保持这个子数组的等差的。所以这里我们需要一个二维数组来模拟动态规划的过程。这里我们动态规划 dp[i][j] 的定义是以 nums[i] 结尾,差值为 j 的最长的满足题意的子数组(有可能是升序也有可能是降序)。这里的等差因为有可能是升序有可能是降序所以等差的差有可能是正数也有可能是负数。这里我们做一个处理,注意题设给的数据范围是从 0 到 500,所以最极端的等差有可能是从正 500 到负 500 所以我们 DP 数组的第二维的长度给 1001。

还是跟300题类似的思路做两层循环,对于每一个 nums[i] ,我们去找 0 - i 范围内每两个数字之间的等差。我们对这个等差无条件 + 500,这样一些小于 0 的差值也就被存到了 DP 数组里面。这个技巧也会在别的题里出现,如果你不想用 hashmap,想用数组存的时候,这个技巧很有用,会提速很多。

对于 dp[i][diff] 而言,更新他的长度也跟 300 题类似。注意最后返回的是 max + 1,因为每个数字自己可以自成一个等差数列。

时间O(n^2)

空间O(n^2)

Java实现

 1 class Solution {
 2     public int longestArithSeqLength(int[] nums) {
 3         // 初始化
 4         // dp是以nums[i]为结尾的,等差差值为k的子序列的长度
 5         // k的范围是0 - 1000
 6         int[][] dp = new int[nums.length][1001];
 7         for (int[] row : dp) {
 8             Arrays.fill(row, 1);
 9         }
10         
11         int max = 1;
12         for (int i = 0; i < nums.length; i++) {
13             for (int j = 0; j < i; j++) {
14                 int diff = (nums[i] - nums[j]) + 500;
15                 dp[i][diff] = dp[j][diff] + 1;
16                 max = Math.max(max, dp[i][diff]);
17             }
18         }
19         return max;
20     }
21 }

 

LIS类相关题目

LeetCode 题目总结

posted @ 2020-11-14 09:49  CNoodle  阅读(300)  评论(0编辑  收藏  举报