Given an array nums
of integers, return the length of the longest arithmetic subsequence in nums
.
Note that:
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
This problem asks for the length of the longest arithmetic subsequence within a given array of integers. An arithmetic subsequence is a sequence where the difference between consecutive elements is constant.
The most efficient approach utilizes dynamic programming. We'll build a table to store the lengths of arithmetic subsequences.
State: dp[i][diff]
represents the length of the longest arithmetic subsequence ending at index i
with a common difference of diff
.
Base Case: dp[i][diff] = 1
for all i
and diff
initially, as each element by itself forms an arithmetic subsequence of length 1.
Transition: For each element nums[i]
, we iterate through the previous elements nums[j]
(where j < i
). If nums[i] - nums[j]
is the common difference diff
, then we can extend the arithmetic subsequence ending at j
by adding nums[i]
. Thus, dp[i][diff] = max(dp[i][diff], dp[j][diff] + 1)
.
Optimization: The common difference can be negative. To avoid negative indices in our dp
array, we can add a constant offset (e.g., 500) to all differences. This shifts the range of differences to non-negative values.
Final Result: The maximum value in the dp
array represents the length of the longest arithmetic subsequence.
d
could be proportional to the range of values in nums
.class Solution:
def longestArithSeqLength(self, nums: List[int]) -> int:
n = len(nums)
if n < 2:
return n # Handle cases with less than 2 elements
dp = {} # Using a dictionary for efficient lookup; key: (index, diff), value: length
max_length = 1
for i in range(1, n):
for j in range(i):
diff = nums[i] - nums[j] + 500 # Add offset to handle negative differences
if (j, diff) in dp:
dp[(i, diff)] = dp[(j, diff)] + 1
else:
dp[(i, diff)] = 2 # Base case: subsequence of length 2
max_length = max(max_length, dp[(i, diff)])
return max_length
import java.util.HashMap;
import java.util.Map;
class Solution {
public int longestArithSeqLength(int[] nums) {
int n = nums.length;
if (n < 2) return n;
Map<String, Integer> dp = new HashMap<>(); //Using a HashMap for efficient lookup
int maxLength = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
int diff = nums[i] - nums[j] + 500; //Offset for negative differences
String key = j + "," + diff;
int length;
if (dp.containsKey(key)) {
length = dp.get(key) + 1;
} else {
length = 2; //Base case
}
dp.put(i + "," + diff, length);
maxLength = Math.max(maxLength, length);
}
}
return maxLength;
}
}
Other languages (C++, Go, TypeScript) would follow similar logic, employing either a 2D array or a hashmap (dictionary) for efficient storage and retrieval of subsequence lengths. The core dynamic programming approach remains consistent.