AlgoMaster Logo

Longest Arithmetic Subsequence

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

This problem asks us to find the longest subsequence (not subarray) where the difference between consecutive elements is constant. The subsequence does not need to be contiguous, which makes it harder than finding arithmetic subarrays.

An arithmetic subsequence is fully described by two things: where it ends and its common difference. Once both are fixed, extending the subsequence means finding an earlier element that sits exactly one step (the common difference) below the current one. That framing drives both approaches below.

Key Constraints

  • 2 <= nums.length <= 1000. With n up to 1,000, an O(n^2) solution runs in about 1 million operations. O(n^3) would be 1 billion, which is too slow for a comfortable margin.
  • 0 <= nums[i] <= 500. Values are non-negative and bounded, so the common difference falls between -500 and 500. The difference therefore fits in a normal int, and a subsequence can be at most 1,000 long, so no count overflows.

Approach 1: Brute Force (Check All Pairs and Extend)

Intuition

A pair of indices already determines a common difference. Pick two indices i and j with i < j, set d = nums[j] - nums[i], then walk forward from j + 1 and greedily take the next element equal to the last value plus d.

The greedy forward scan is safe here because the next value the chain needs, last + d, is a single fixed number. Any element equal to it extends the chain by one, and taking the earliest one leaves the most array left to extend further. So scanning left to right and grabbing the first match never undercounts.

Algorithm

  1. For each pair of indices (i, j) with i < j, compute the common difference d = nums[j] - nums[i].
  2. Track last = nums[j] and a running length of 2.
  3. Scan from j + 1 to the end. Whenever an element equals last + d, increment the length and move last forward to it.
  4. Track the global maximum across all pairs and return it.

Example Walkthrough

Input:

0
9
1
4
2
7
3
2
4
10
nums

We start with maxLen = 2 and try every pair.

  • Pair (0, 1): d = 4 - 9 = -5. Scan from index 2 for -1, -6, ... none found. Length 2.
  • Pair (0, 2): d = 7 - 9 = -2. Looking for 5, 3, ... index 3 is 2, not 5. Length 2.
  • Pair (1, 2): d = 7 - 4 = 3. Looking for 10 from index 3. nums[3] = 2 (skip), nums[4] = 10 (match). Chain [4, 7, 10], length 3. maxLen becomes 3.
  • Pair (1, 4): d = 10 - 4 = 6. Nothing after index 4. Length 2.
  • Pair (3, 4): d = 10 - 2 = 8. Nothing after index 4. Length 2.

Every remaining pair gives length 2, so the answer is 3.

3
result

Code

The forward scan repeats work: every pair rescans the tail of the array. The next approach removes that scan by storing, for each index and each common difference, how long a chain already ends there. Extending then becomes a single lookup.

Approach 2: Dynamic Programming with Hash Map

Intuition

If we already know the longest arithmetic subsequence ending at index j with common difference d, then any later index i with nums[i] - nums[j] == d extends it by one in O(1) time. We do not need to rescan anything.

Define dp[i] as a hash map where dp[i][d] holds the length of the longest arithmetic subsequence that ends at index i and has common difference d. Iterating j over all earlier indices for each i fills these maps, and the largest value across all of them is the answer.

Algorithm

  1. Create an array of hash maps dp, where dp[i] maps each common difference to the length of the longest arithmetic subsequence ending at index i.
  2. For each index i from 1 to n-1:
    • For each index j from 0 to i-1:
      • Compute diff = nums[i] - nums[j].
      • If dp[j] contains diff, set dp[i][diff] = dp[j][diff] + 1.
      • Otherwise, set dp[i][diff] = 2 (the pair nums[j], nums[i]).
      • Update the global maximum.
  3. Return the global maximum.

Example Walkthrough

1Initialize: dp = [{}, {}, {}, {}, {}], maxLen = 2
0
9
1
4
2
7
3
2
4
10
1/7

Code