VOOZH about

URL: https://www.geeksforgeeks.org/dsa/longest-subsequence-such-that-difference-between-adjacents-is-one/

⇱ Longest subsequence such that difference between adjacents is one - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Longest subsequence such that difference between adjacents is one

Last Updated : 29 Nov, 2024

Given an array arr[] of size n, the task is to find the longest subsequence such that the absolute difference between adjacent elements is 1.

Examples: 

Input: arr[] = [10, 9, 4, 5, 4, 8, 6]
Output: 3
Explanation: The three possible subsequences of length 3 are [10, 9, 8], [4, 5, 4], and [4, 5, 6], where adjacent elements have a absolute difference of 1. No valid subsequence of greater length could be formed.

Input: arr[] = [1, 2, 3, 4, 5]
Output: 5
Explanation: All the elements can be included in the valid subsequence.

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

For the recursive approach, we will consider two cases at each step:

  • If the element satisfies the condition (the absolute difference between adjacent elements is 1), we include it in the subsequence and move on to the next element.
  • else, we skip the current element and move on to the next one.

Mathematically, the recurrence relation will look like the following:

  • longestSubseq(arr, idx, prev) = max(longestSubseq(arr, idx + 1, prev), 1 + longestSubseq(arr, idx + 1, idx))

Base Case:

  • When idx == arr.size(), we have reached the end of the array, so return 0 (since no more elements can be included).

Output
3

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

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:

1. Optimal Substructure: The solution to finding the longest subsequence such that the difference between adjacent elements is one can be derived from the optimal solutions of smaller subproblems. Specifically, for any given idx (current index) and prev (previous index in the subsequence), we can express the recursive relation as follows:

  • subseqHelper(idx, prev) = max(subseqHelper(idx + 1, prev), 1 + subseqHelper(idx + 1, idx))

2. Overlapping Subproblems: When implementing a recursive approach to solve the problem, we observe that many subproblems are computed multiple times. For example, when computing subseqHelper(0, -1) for an array arr = [10, 9, 4, 5], the subproblem subseqHelper(2, -1) may be computed multiple times. To avoid this repetition, we use memoization to store the results of previously computed subproblems.

The recursive solution involves two parameters:

  • idx (the current index in the array).
  • prev (the index of the last included element in the subsequence).

We need to track both parameters, so we create a 2D array memo of size (n) x (n+1). We initialize the 2D array memo with -1 to indicate that no subproblems have been computed yet. Before computing a result, we check if the value at memo[idx][prev+1] is -1. If it is, we compute and store the result. Otherwise, we return the stored result.


Output
3

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

The approach is similar to the recursive method, but instead of breaking down the problem recursively, we iteratively build the solution in a bottom-up manner.
Instead of using recursion, we utilize a hashmap based dynamic programming table (dp) to store the lengths of the longest subsequences. This helps us efficiently calculate and update the subsequence lengths for all possible values of array elements.

Dynamic Programming Relation:

dp[x] represents the length of the longest subsequence ending with the element x.

For every element arr[i] in the array: If arr[i] + 1 or arr[i] - 1 exists in dp:

  • dp[arr[i]] = 1 + max(dp[arr[i] + 1], dp[arr[i] - 1]);

This means we can extend the subsequences ending with arr[i] + 1 or arr[i] - 1 by including arr[i].

Otherwise, start a new subsequence:

  • dp[arr[i]] = 1;

Output
3
Comment
Article Tags: