VOOZH about

URL: https://www.geeksforgeeks.org/dsa/longest-arithmetic-progression-dp-35/

⇱ Longest Arithmetic Progression - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Longest Arithmetic Progression

Last Updated : 22 Nov, 2024

Given an array arr[] of sorted integers and distinct positive integers, find the length of the Longest Arithmetic Progression in it.
Note: A sequence seq is an arithmetic progression if seq[i + 1] - seq[i] are all the same value (for 0 <= i < seq.length - 1).

Examples:

Input: arr[] = [1, 7, 10, 15, 27, 29]
Output: 3
Explanation: The longest arithmetic progression is [1, 15, 29] having common difference 14.

Input: arr []= [5, 10, 15, 20, 25, 30]
Output: 6
Explanation: The whole set is in AP having common difference 5.

Using Recursion - O(n^3) Time and O(n) Space

For the recursive approach to finding the length of the longest arithmetic progression (AP), there are two main cases:

Include the current element in the AP

  • If the difference between the current element and a previous element matches the desired difference, extend the AP by considering the current element.

Mathematically: solve(i, diff) = 1 + solve(j, diff) for all j < i such that arr[i] - arr[j] = diff.

Exclude the current element from the AP:

  • Skip the current element and proceed with the remaining elements.

Mathematically: solve(i, diff) = max(solve(i - 1, diff), solve(j, diff)) where j < i.

Base Case: solve(i, diff) = 0 when i < 0. This means if there are no elements left to form an AP, the length is zero.

For every pair of indices (i, j), compute the maximum AP length as:

  • Length = max(Length, 2 + solve(i, arr[j] - arr[i]))

Output
3

Using Top-Down DP (Memoization) - O(n^2) Time and O(n^2) Space

1. Optimal Substructure: The solution to the problem can be derived from optimal solutions of smaller subproblems. Specifically, If the difference diff between two elements matches the desired difference for an AP ending at index, we extend the progression:

  • solve(index, diff) = 1 + solve(j, diff) where j < index and arr[index] - arr[j] = diff.

If no such j exists, the result for solve(index, diff) remains the same.

2. Overlapping Subproblems: In the recursive solution, many subproblems are recomputed multiple times. For example, solve(i, diff) for a specific index and difference can be computed repeatedly for different calls in the recursion tree. Memoization stores these results to avoid redundant calculations.
If the value for solve(index, diff) is already computed and stored in memo[index][diff], it is directly returned to avoid redundant computation:

  • solve(index, diff) = memo[index][diff], if memo[index][diff] exists.

Output
3

Using Bottom-Up DP (Tabulation) - O(n^2) Time and O(n^2) Space

The tabulation approach iteratively builds the solution in a bottom-up manner, avoiding the use of recursion. Instead of solving smaller subproblems recursively, we use a table to store and update solutions for progressively larger subproblems.

We will create a 2D table of size n x diffRange, where dp[i][diff] represents the length of the arithmetic progression (AP) ending at index i with a common difference of diff.

The dynamic programming relation is as follows:

  • For each pair of indices (j, i) where j < i: Calculate the common difference: diff = arr[i] - arr[j]
  • If there is an AP ending at index j with the same diff: dp[i][diff] = dp[j][diff] + 1
  • Otherwise, start a new AP of length 2: dp[i][diff] = 2

Output
3
Comment