Problem Statement
Given a sequence of N numbers, find the longest increasing subsequence (it’s as simple as that).
Example: The length of the LIS of [10, 22, 9, 33, 21, 50, 41, 60, 80] is 6, and the LIS itself is [10, 22, 9, 33, 21, 50, 41, 60, 80] \(\rightarrow\) [10, 22, 33, 50, 60, 80]
General Idea 1 | \(O(n^2)\)
This solution consists of 2 arrays:
LIS[N]
\(\rightarrow\) Stores the length of the LIS ending at elementi
previous[N]
\(\rightarrow\) Back-reference to previous element of the LIS ending ati
The gist of the solution is to fill up the LIS
array, it’s that simple.
To accomplish this, we loop over each element i
in the original sequence.
Now, for each element j
that came before i
(as in lower in index than i
),
we check if both array[j] < array[i]
and LIS[j] + 1 > LIS[i]
are satisfied.
array[j] < array[i]
needs to be true if we are looking for the longest increasing subsequence. This condition can be changed toarray[j] > array[i]
if we were looking for the longest decreasing subsequence.LIS[j] + 1 > LIS[i]
needs to be true if we are looking for the longest increasing subsequence i.e is the sequence coming fromj
longer than the current sequence ending ati
?
Using these two conditions, we’re able to fill up the LIS
array pretty easily.
The maximum length of the LIS will be the maximum value contained in the LIS
array.
But that’s not it. Using the previous
array, we’re also to rebuild the sequence
itself. Check out the code below for details on how we can accomplish this.
To recap, we use the LIS
array to find the length of the longest subsequence
and the previous
array to find the sequence itself.
Code
C++ code below
General Idea 2 | \(O(n \space logn)\)
This one is much shorter, faster, but harder to wrap your head around.
Geeksforgeeks does a much better job at explaining it than I will ever do, so hop on over there if you want the detailed explanation of the logic behind it.
Code
C++ code below