Given an input vector of numbers find the longest monotonically increasing subsequence

The longest increasing subsequence problem is a common example of dynamic programming. Given an input vector \( v \) of \( n \) elements, the longest increasing subsequence can be found in exponential time by recursively evaluating all the subsequences for monotonicity and maximum length or in \( O(n \log{n}) \) time with a dynamic programming approach.

The key to the recursion expression lies in the following observations:

  • An element greater than any previously encountered increases the length of all the previous subsequences by one
  • An element which is not the greatest one encountered till this point can be used to reduce the final value of a previous subsequence

In case of an input vector \( v = { 1,2,4,3 } \) the longest subsequence encountered till element 4 is \( { 1,2,4 } \). When element 3 is encountered it cannot be appended since it’s less than 4, but it can be used in place of 4 to increase the length of the subsequence \( {1,2} \) since ending with 3 instead of 4 ensures a better chance to encounter a highest value in the future (and thus increasing the length of the sequence).

Let \( lis(i) \) be the best-candidate terminal element for the subsequence with length \( i \), it follows that

\[lis(i) = v(t) \begin{cases} v(t) > lis(i-1)\\ v(t) = min \{ v(j) > lis(i-1), \ j < t \} \end{cases}\]
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;

// Finds the length of the longest increasing subsequence in O(NlogN)

int longestIncreasingSubsequence(vector<int>& vec) {

  // Notice: this code assumes no duplicates

  assert(unique(vec.begin(), vec.end()) == vec.end() && "No duplicates allowed");

  // lis[i] is the last element of the sequence with size i

  vector<int> lis(vec.size(), -1);
  int lis_max = 0;
  for (int i = 0; i < vec.size(); ++i) {
    // Find the smallest value greater than vec[i] in lis

    int lo = 0;
    int hi = lis_max - 1;
    while (lo <= hi) {
      int mid = static_cast<int>(ceil((lo + hi) / 2.0f));
      if (vec[i] > lis[mid])
        lo = mid + 1;
      else
        hi = mid - 1;
    }
    if (lo >= lis_max)
      ++lis_max;
    lis[lo] = vec[i];
  }
  return lis_max;
}

int main() {

  vector<int> vec = { 1,2,4,3 };
  cout << longestIncreasingSubsequence(vec); // 3


  return 0;
}