Longest Decreasing Subsequence Problem

The longest decreasing subsequence problem is to find a subsequence of a given sequence in which the subsequence’s elements are in sorted order, highest to lowest, and in which the subsequence is as long as possible. This subsequence is not necessarily contiguous, or unique.

 

For example, consider below subsequence

[0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
 

Longest decreasing subsequence is [12, 10, 9, 5, 3]

This subsequence has length 5; the input sequence has no 7-member decreasing subsequences.

The longest decreasing subsequence in this example is not unique: for instance,
[12, 10, 6, 5, 3] is another decreasing subsequences of equal length in the same input sequence.

 


 

We can use recursion to solve this problem. For each item, there are two possibilities –
 

1. We include current item in LDS if it is smaller than the previous element in LDS and recurse for remaining items.
 
2. We exclude current item from LDS and recurse for remaining items.
 

Finally, we return maximum value we get by including or excluding current item. The base case of the recursion would be when no items are left.

 
C++ implementation –
 

Download   Run Code

Output:

Length of LDS is 5

 
The time complexity of above solution is exponential and auxiliary space used by the program is O(1).

 


 

The problem has an optimal substructure. That means the problem can be broken down into smaller, simple “subproblems”, which can further be divided into yet simpler, smaller subproblems until the solution becomes trivial. Above solution also exhibits overlapping subproblems. If we draw the recursion tree of the solution, we can see that the same sub-problems are getting computed again and again.

We know that problems having optimal substructure and overlapping subproblems can be solved by using Dynamic Programming, in which subproblem solutions are Memoized rather than computed again and again. The Memoized version follows the top-down approach, since we first break the problem into subproblems and then calculate and store values.

We can also solve this problem in bottom-up manner. In the bottom-up approach, we solve smaller sub-problems first, then solve larger sub-problems from them. The following bottom-up approach computes L[i], for each 0 <= i < n, which stores the length of the longest decreasing subsequence of subarray arr[0..i] that ends with arr[i]. To calculate L[i], we consider LDS of all smaller values of i (say j) already computed and pick the maximum L[j] where arr[j] is more than the current element arr[i]. It has the same asymptotic run-time as Memoization but no recursion overhead.

 
C++ implementation –
 

Download   Run Code

Output:

Length of LDS is 5

 
The time complexity of above solution is O(n2) and auxiliary space used by the program is O(n).

 


 

How to print LDS?

Above solutions only print the length of LDS but do not actually print LDS itself. To print the LDS, we actually have to store the longest decreasing subsequence in lookup table instead of storing just LDS length.
 

For example, consider below array

A[] = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

The Longest Decreasing Subsequence LDS[i] of subarray A[0..i] that ends with A[i] are -


LDS[0] - 0
LDS[1] - 8
LDS[2] - 8 4
LDS[3] - 12
LDS[4] - 8 4 2
LDS[5] - 12 10
LDS[6] - 12 10 6
LDS[7] - 14
LDS[8] - 8 4 2 1
LDS[9] - 12 10 9
LDS[10] - 12 10 6 5
LDS[11] - 14 13
LDS[12] - 12 10 6 5 3
LDS[13] - 14 13 11
LDS[14] - 12 10 9 7
LDS[15] - 15

 
C++ implementation –
 

Download   Run Code

Output:

12 10 6 5 3

 
The time complexity of above solution is O(n2) and auxiliary space used by the program is O(n2).
 

Thanks for reading.




Please use ideone or C++ Shell or any other online compiler link to post code in comments.
Like us? Please spread the word and help us grow. Happy coding 🙂
 





Leave a Reply

Notify of
avatar
wpDiscuz