Skip to content
Related Articles
Get the best out of our app
GFG App
Open App
geeksforgeeks
Browser
Continue

Related Articles

Longest Increasing Subsequence Size (N log N)

Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article

Given an array of random numbers. Find the longest increasing subsequence (LIS) in the array. I know many of you might have read recursive and dynamic programming (DP) solutions. There are few requests for O(N log N) algo in the forum posts.

BRUTE METHOD:

Intuition:

  1. We make an array to store lengths of LIS ending at that particular element.
  2. We traverse through the array and for each element, we traverse from beginning till that element and see if there is element which is smaller than the current element .
  3. After this iteration we store the max value+1 in the current index array.
  4. Atlast the maximum value in the array is the ans.

Implementation:

Java




// Java program to find LIS.
 
import java.io.*;
import java.util.*;
 
class GFG {
    static int longestSubsequence(int size, int a[])
    {
        // code here
        int[] dp = new int[size];
        int maxlen = 0;
        for (int i = 0; i < size; i++) {
            int max = 0;
            for (int j = 0; j < i; j++) {
                if (a[j] < a[i])
                    max = Math.max(dp[j], max);
            }
            dp[i] = max + 1;
            maxlen = Math.max(dp[i], maxlen);
        }
        return maxlen;
    }
    public static void main(String[] args)
    {
        int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = A.length;
        System.out.println(
            "Length of Longest Increasing Subsequence is "
            + longestSubsequence(n, A));
    }
}
// This code is contributed by Raunak Singh


Output

Length of Longest Increasing Subsequence is 6

Time Complexity: O(N^2) since we are traversing twice for each element to find LIS.
Space Complexity: O(N) since we are using an array to store lengths.

For the time being, forget about recursive and DP solutions. Let us take small samples and extend the solution to large instances. Even though it may look complex at first time, once if we understood the logic, coding is simple.

Consider an input array A = {2, 5, 3}.
By observation, we know that the LIS is either {2, 3} or {2, 5}. Note that only strictly increasing sequences are considered here.

Let us add two more elements, say 7, 11 to the array. These elements will extend the existing sequences. Now the increasing sequences are {2, 3, 7, 11} and {2, 5, 7, 11} for the input array {2, 5, 3, 7, 11}.

Further, we add one more element, say 8 to the array i.e. input array becomes {2, 5, 3, 7, 11, 8}. Note that the latest element 8 is greater than smallest element of any active sequence (will discuss shortly about active sequences).
How can we extend the existing sequences with 8? First of all, can 8 be part of LIS? If yes, how? If we want to add 8, it should come after 7 (by replacing 11).

Since the approach is offline (what we mean by offline?), we are not sure whether adding 8 will extend the series or not. Assume there is 9 in the input array, say {2, 5, 3, 7, 11, 8, 7, 9 …}. We can replace 11 with 8, as there is potentially best candidate (9) that can extend the new series {2, 3, 7, 8} or {2, 5, 7, 8}.
Our observation is, assume that the end element of largest sequence is E. We can add (replace) current element A[i] to the existing sequence if there is an element A[j] (j > i) such that E < A[i] < A[j] or (E > A[i] < A[j] – for replace). In the above example, E = 11, A[i] = 8 and A[j] = 9.
In case of our original array {2, 5, 3}, note that we face same situation when we are adding 3 to increasing sequence {2, 5}. I just created two increasing sequences to make explanation simple. Instead of two sequences, 3 can replace 5 in the sequence {2, 5}.
I know it will be confusing, I will clear it shortly!
The question is, when will it be safe to add or replace an element in the existing sequence?
Let us consider another sample A = {2, 5, 3}. Say, the next element is 1. How can it extend the current sequences {2, 3} or {2, 5}. Obviously, it can’t extend either. Yet, there is a potential that the new smallest element can be start of an LIS. To make it clear, consider the array is {2, 5, 3, 1, 2, 3, 4, 5, 6}. Making 1 as new sequence will create new sequence which is largest.
The observation is, when we encounter new smallest element in the array, it can be a potential candidate to start new sequence.
From the observations, we need to maintain lists of increasing sequences.
In general, we have set of active lists of varying length. We are adding an element A[i] to these lists. We scan the lists (for end elements) in decreasing order of their length. We will verify the end elements of all the lists to find a list whose end element is smaller than A[i] (floor value).
Our strategy determined by the following conditions, 
 

1. If A[i] is smallest among all end 
   candidates of active lists, we will start 
   new active list of length 1.
2. If A[i] is largest among all end candidates of 
  active lists, we will clone the largest active 
  list, and extend it by A[i].
3. If A[i] is in between, we will find a list with 
  largest end element that is smaller than A[i]. 
  Clone and extend this list by A[i]. We will discard all
  other lists of same length as that of this modified list.

Note that at any instance during our construction of active lists, the following condition is maintained.
“end element of smaller list is smaller than end elements of larger lists”.
It will be clear with an example, let us take example from wiki {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}. 
 

A[0] = 0. Case 1. There are no active lists, create one.
0.
-----------------------------------------------------------------------------
A[1] = 8. Case 2. Clone and extend.
0.
0, 8.
-----------------------------------------------------------------------------
A[2] = 4. Case 3. Clone, extend and discard.
0.
0, 4.
0, 8. Discarded
-----------------------------------------------------------------------------
A[3] = 12. Case 2. Clone and extend.
0.
0, 4.
0, 4, 12.
-----------------------------------------------------------------------------
A[4] = 2. Case 3. Clone, extend and discard.
0.
0, 2.
0, 4. Discarded.
0, 4, 12.
-----------------------------------------------------------------------------
A[5] = 10. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 10.
0, 4, 12. Discarded.
-----------------------------------------------------------------------------
A[6] = 6. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 6.
0, 2, 10. Discarded.
-----------------------------------------------------------------------------
A[7] = 14. Case 2. Clone and extend.
0.
0, 2.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[8] = 1. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2. Discarded.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[9] = 9. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2, 6.
0, 2, 6, 9.
0, 2, 6, 14. Discarded.
-----------------------------------------------------------------------------
A[10] = 5. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 5.
0, 2, 6. Discarded.
0, 2, 6, 9.
-----------------------------------------------------------------------------
A[11] = 13. Case 2. Clone and extend.
0.
0, 1.
0, 1, 5.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[12] = 3. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 5. Discarded.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[13] = 11. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 2, 6, 9.
0, 2, 6, 9, 11.
0, 2, 6, 9, 13. Discarded.
-----------------------------------------------------------------------------
A[14] = 7. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9. Discarded.
0, 2, 6, 9, 11.
----------------------------------------------------------------------------
A[15] = 15. Case 2. Clone and extend.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9, 11.
0, 2, 6, 9, 11, 15. <-- LIS List
----------------------------------------------------------------------------

It is required to understand above strategy to devise an algorithm. Also, ensure we have maintained the condition, “end element of smaller list is smaller than end elements of larger lists“. Try with few other examples, before reading further. It is important to understand what happening to end elements.
Algorithm:
Querying length of longest is fairly easy. Note that we are dealing with end elements only. We need not to maintain all the lists. We can store the end elements in an array. Discarding operation can be simulated with replacement, and extending a list is analogous to adding more elements to array.
We will use an auxiliary array to keep end elements. The maximum length of this array is that of input. In the worst case the array divided into N lists of size one (note that it doesn’t lead to worst case complexity). To discard an element, we will trace ceil value of A[i] in auxiliary array (again observe the end elements in your rough work), and replace ceil value with A[i]. We extend a list by adding element to auxiliary array. We also maintain a counter to keep track of auxiliary array length.
Bonus: You have learnt Patience Sorting technique partially 🙂
Here is a proverb, “Tell me and I will forget. Show me and I will remember. Involve me and I will understand.” So, pick a suit from deck of cards. Find the longest increasing sub-sequence of cards from the shuffled suit. You will never forget the approach. 🙂
Update – 17 July, 2016: Quite impressive responses from the readers and few sites referring the post, feeling happy as my hardwork helping others. It looks like readers are not doing any homework prior to posting comments. Requesting to run through some examples after reading the article, and please do your work on paper (don’t use editor/compiler). The request is to help yourself. Profess to ‘know’ is different from real understanding (no disrespect). Given below was my personal experience.
Initial content preparation took roughly 6 hours to me. But, it was a good lesson. I finished initial code in an hour. When I start writing content to explain the reader, I realized I didn’t understand the cases. Took my note book (I have habit of maintaining binded note book to keep track of my rough work), and after few hours I filled nearly 15 pages of rough work. Whatever the content you are seeing in the gray colored example is from these pages. All the thought process for the solution triggered by a note in the book ‘Introduction to Algorithms by Udi Manber’, I strongly recommend to practice the book.
I suspect, many readers might not get the logic behind CeilIndex (binary search). I leave it as an exercise to the reader to understand how it works. Run through few examples on paper. I realized I have already covered the algorithm in another post.
Update – 5th August, 2016:
The following link worth referring after you do your work. I got to know the link via my recently created Disqus profile. The link has explanation of approach mentioned in the Wiki.
http://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-subsequence-using-dynamic-programming
Given below is code to find length of LIS (updated to C++11 code, no C-style arrays),
 

C++




#include <iostream>
#include <vector>
 
// Binary search (note boundaries in the caller)
int CeilIndex(std::vector<int>& v, int l, int r, int key)
{
    while (r - l > 1) {
        int m = l + (r - l) / 2;
        if (v[m] >= key)
            r = m;
        else
            l = m;
    }
 
    return r;
}
 
int LongestIncreasingSubsequenceLength(std::vector<int>& v)
{
    if (v.size() == 0)
        return 0;
 
    std::vector<int> tail(v.size(), 0);
    int length = 1; // always points empty slot in tail
 
    tail[0] = v[0];
    for (size_t i = 1; i < v.size(); i++) {
 
        // new smallest value
        if (v[i] < tail[0])
            tail[0] = v[i];
 
        // v[i] extends largest subsequence
        else if (v[i] > tail[length - 1])
            tail[length++] = v[i];
 
        // v[i] will become end candidate of an existing
        // subsequence or Throw away larger elements in all
        // LIS, to make room for upcoming greater elements
        // than v[i] (and also, v[i] would have already
        // appeared in one of LIS, identify the location
        // and replace it)
        else
            tail[CeilIndex(tail, -1, length - 1, v[i])] = v[i];
    }
 
    return length;
}
 
int main()
{
    std::vector<int> v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    std::cout << "Length of Longest Increasing Subsequence is "
              << LongestIncreasingSubsequenceLength(v) << '\n';
    return 0;
}


Java




// Java program to find length of longest increasing subsequence
// in O(n Log n) time
import java.io.*;
import java.util.*;
import java.lang.Math;
 
class LIS {
    // Binary search (note boundaries in the caller)
    // A[] is ceilIndex in the caller
    static int CeilIndex(int A[], int l, int r, int key)
    {
        while (r - l > 1) {
            int m = l + (r - l) / 2;
            if (A[m] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequenceLength(int A[], int size)
    {
        // Add boundary case, when array size is one
 
        int[] tailTable = new int[size];
        int len; // always points empty slot
 
        tailTable[0] = A[0];
        len = 1;
        for (int i = 1; i < size; i++) {
            if (A[i] < tailTable[0])
                // new smallest value
                tailTable[0] = A[i];
 
            else if (A[i] > tailTable[len - 1])
                // A[i] wants to extend largest subsequence
                tailTable[len++] = A[i];
 
            else
                // A[i] wants to be current end candidate of an existing
                // subsequence. It will replace ceil value in tailTable
                tailTable[CeilIndex(tailTable, -1, len - 1, A[i])] = A[i];
        }
 
        return len;
    }
 
    // Driver program to test above function
    public static void main(String[] args)
    {
        int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = A.length;
        System.out.println("Length of Longest Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n));
    }
}
/* This code is contributed by Devesh Agrawal*/


Python3




# Python program to find
# length of longest
# increasing subsequence
# in O(n Log n) time
 
# Binary search (note
# boundaries in the caller)
# A[] is ceilIndex
# in the caller
def CeilIndex(A, l, r, key):
 
    while (r - l > 1):
     
        m = l + (r - l)//2
        if (A[m] >= key):
            r = m
        else:
            l = m
    return r
  
def LongestIncreasingSubsequenceLength(A, size):
 
    # Add boundary case,
    # when array size is one
  
    tailTable = [0 for i in range(size + 1)]
    len = 0 # always points empty slot
  
    tailTable[0] = A[0]
    len = 1
    for i in range(1, size):
     
        if (A[i] < tailTable[0]):
 
            # new smallest value
            tailTable[0] = A[i]
  
        elif (A[i] > tailTable[len-1]):
 
            # A[i] wants to extend
            # largest subsequence
            tailTable[len] = A[i]
            len+= 1
  
        else:
            # A[i] wants to be current
            # end candidate of an existing
            # subsequence. It will replace
            # ceil value in tailTable
            tailTable[CeilIndex(tailTable, -1, len-1, A[i])] = A[i]
         
  
    return len
 
  
# Driver program to
# test above function
 
A = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ]
n = len(A)
 
print("Length of Longest Increasing Subsequence is ",
       LongestIncreasingSubsequenceLength(A, n))
 
# This code is contributed
# by Anant Agarwal.


C#




// C# program to find length of longest
// increasing subsequence in O(n Log n)
// time
using System;
 
class GFG {
 
    // Binary search (note boundaries
    // in the caller) A[] is ceilIndex
    // in the caller
    static int CeilIndex(int[] A, int l,
                         int r, int key)
    {
        while (r - l > 1) {
            int m = l + (r - l) / 2;
 
            if (A[m] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequenceLength(
        int[] A, int size)
    {
 
        // Add boundary case, when array size
        // is one
 
        int[] tailTable = new int[size];
        int len; // always points empty slot
 
        tailTable[0] = A[0];
        len = 1;
        for (int i = 1; i < size; i++) {
            if (A[i] < tailTable[0])
                // new smallest value
                tailTable[0] = A[i];
 
            else if (A[i] > tailTable[len - 1])
 
                // A[i] wants to extend largest
                // subsequence
                tailTable[len++] = A[i];
 
            else
 
                // A[i] wants to be current end
                // candidate of an existing
                // subsequence. It will replace
                // ceil value in tailTable
                tailTable[CeilIndex(tailTable, -1,
                                    len - 1, A[i])]
                    = A[i];
        }
 
        return len;
    }
 
    // Driver program to test above function
    public static void Main()
    {
        int[] A = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = A.Length;
        Console.Write("Length of Longest "
                      + "Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n));
    }
}
 
// This code is contributed by nitin mittal.


PHP




<?php
// PHP program to find
// length of longest
// increasing subsequence
// in O(n Log n) time
 
// Binary search (note
// boundaries in the caller)
// A[] is ceilIndex
// in the caller
function CeilIndex($A, $l, $r, $key)
{
    while ($r - $l > 1)
    {
        $m = (int)($l + ($r - $l)/2);
        if ($A[$m] >= $key)
            $r = $m;
        else
            $l = $m;
    }
    return $r;
}
 
function LongestIncreasingSubsequenceLength($A, $size)
{
    // Add boundary case,
    // when array size is one
 
    $tailTable = array_fill(0, ($size + 1), 0);
    $len = 0; // always points empty slot
 
    $tailTable[0] = $A[0];
    $len = 1;
    for($i = 1; $i < $size; $i++)
    {
     
        if ($A[$i] < $tailTable[0])
            // new smallest value
            $tailTable[0] = $A[$i];
 
        else if ($A[$i] > $tailTable[$len-1])
        {
            // A[i] wants to extend
            // largest subsequence
            $tailTable[$len] = $A[$i];
            $len++;
        }
        else
            // A[i] wants to be current
            // end candidate of an existing
            // subsequence. It will replace
            // ceil value in tailTable
            $tailTable[CeilIndex($tailTable, -1, $len-1, $A[$i])] = $A[$i];
         
    }
    return $len;
}
 
// Driver program to
// test above function
$A = array( 2, 5, 3, 7, 11, 8, 10, 13, 6 );
$n = count($A);
 
print("Length of Longest Increasing Subsequence is ".
        LongestIncreasingSubsequenceLength($A, $n));
 
// This code is contributed by chandan_jnu
?>


Javascript




<script>
// javascript program to find length of longest increasing subsequence
// in O(n Log n) time
 
    // Binary search (note boundaries in the caller)
    // A is ceilIndex in the caller
    function CeilIndex(A , l , r , key) {
        while (r - l > 1) {
            var m = l + parseInt((r - l) / 2);
            if (A[m] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    function LongestIncreasingSubsequenceLength(A , size)
    {
     
        // Add boundary case, when array size is one
 
        var tailTable = Array(size).fill(0);
        var len; // always points empty slot
 
        tailTable[0] = A[0];
        len = 1;
        for (var i = 1; i < size; i++) {
            if (A[i] < tailTable[0])
                // new smallest value
                tailTable[0] = A[i];
 
            else if (A[i] > tailTable[len - 1])
                // A[i] wants to extend largest subsequence
                tailTable[len++] = A[i];
 
            else
                // A[i] wants to be current end candidate of an existing
                // subsequence. It will replace ceil value in tailTable
                tailTable[CeilIndex(tailTable, -1, len - 1, A[i])] = A[i];
        }
 
        return len;
    }
 
    // Driver program to test above function
        var A = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ];
        var n = A.length;
        document.write("Length of Longest Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n));
 
// This code is contributed by gauravrajput1
</script>


Output

Length of Longest Increasing Subsequence is 6

Complexity:
The loop runs for N elements. In the worst case (what is worst case input?), we may end up querying ceil value using binary search (log i) for many A[i].
Therefore, T(n) < O( log N! )  = O(N log N). Analyse to ensure that the upper and lower bounds are also O( N log N ). The complexity is THETA (N log N).

Auxiliary Space: O(N)
Exercises:
1. Design an algorithm to construct the longest increasing list. Also, model your solution using DAGs.
2. Design an algorithm to construct all increasing lists of equal longest size.
3. Is the above algorithm an online algorithm?
4. Design an algorithm to construct the longest decreasing list..
Alternate implementation in various languages using their built in binary search functions are given below: 

CPP




#include <bits/stdc++.h>
using namespace std;
 
int LongestIncreasingSubsequenceLength(std::vector<int>& v)
{
    if (v.size() == 0) // boundary case
        return 0;
 
    std::vector<int> tail(v.size(), 0);
    int length = 1; // always points empty slot in tail
 
    tail[0] = v[0];
 
    for (int i = 1; i < v.size(); i++) {
 
        // Do binary search for the element in
        // the range from begin to begin + length
        auto b = tail.begin(), e = tail.begin() + length;
        auto it = lower_bound(b, e, v[i]);
 
        // If not present change the tail element to v[i]
        if (it == tail.begin() + length)
            tail[length++] = v[i];
        else
            *it = v[i];
    }
 
    return length;
}
 
int main()
{
    std::vector<int> v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    std::cout
        << "Length of Longest Increasing Subsequence is "
        << LongestIncreasingSubsequenceLength(v);
    return 0;
}


Java




import java.io.*;
import java.lang.Math;
import java.util.*;
 
class LIS {
    static int LongestIncreasingSubsequenceLength(int v[])
    {
        if (v.length == 0) // boundary case
            return 0;
 
        int[] tail = new int[v.length];
        int length = 1; // always points empty slot in tail
        tail[0] = v[0];
 
        for (int i = 1; i < v.length; i++) {
 
            if (v[i] > tail[length - 1]) {
                // v[i] extends the largest subsequence
                tail[length++] = v[i];
            }
            else {
                // v[i] will extend a subsequence and
                // discard older subsequence
 
                // find the largest value just smaller than
                // v[i] in tail
 
                // to find that value do binary search for
                // the v[i] in the range from begin to 0 +
                // length
                int idx = Arrays.binarySearch(
                    tail, 0, length - 1, v[i]);
 
                // binarySearch in java returns negative
                // value if searched element is not found in
                // array
 
                // this negative value stores the
                // appropriate place where the element is
                // supposed to be stored
                if (idx < 0)
                    idx = -1 * idx - 1;
 
                // replacing the existing subsequence with
                // new end value
                tail[idx] = v[i];
            }
        }
        return length;
    }
 
    // Driver program to test above function
    public static void main(String[] args)
    {
        int v[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        System.out.println(
            "Length of Longest Increasing Subsequence is "
            + LongestIncreasingSubsequenceLength(v));
    }
}
 
/* This code is contributed by Serjeel Ranjan */


Python3




from bisect import bisect_left
 
 
def LongestIncreasingSubsequenceLength(v):
    if len(v) == 0# boundary case
        return 0
 
    tail = [0 for i in range(len(v) + 1)]
    length = 1  # always points empty slot in tail
 
    tail[0] = v[0]
 
    for i in range(1, len(v)):
        if v[i] > tail[length-1]:
            # v[i] extends the largest subsequence
            tail[length] = v[i]
            length += 1
 
        else:
            # v[i] will extend a subsequence and discard older subsequence
 
            # find the largest value just smaller than v[i] in tail
 
            # to find that value do binary search for the v[i] in
            # the range from begin to 0 + length
 
            # bisect function either returns index where element is found
            # or the appropriate index at which element should be placed
 
            # finally replace the existing subsequence with new end value
            tail[bisect_left(tail, v[i], 0, length-1)] = v[i]
 
    return length
 
 
# Driver program to test above function
v = [2, 5, 3, 7, 11, 8, 10, 13, 6]
print("Length of Longest Increasing Subsequence is ",
      LongestIncreasingSubsequenceLength(v))
 
# This code is contributed by Serjeel Ranjan


C#




using System;
using System.Collections.Generic;
 
public class LIS {
    public
static int lowerBound(int[] a, int low, int high, int element){
    while(low < high){
        int middle = low + (high - low)/2;
        if(element > a[middle])
            low = middle + 1;
        else
            high = middle;
    }
    return low;
    static int longestIncreasingSubsequenceLength(int []v)
    {
        if (v.GetLength(0) == 0) // boundary case
            return 0;
 
        int[] tail = new int[v.GetLength(0)];
        int length = 1; // always points empty slot in tail
        tail[0] = v[0];
 
        for (int i = 1; i < v.GetLength(0); i++) {
 
            if (v[i] > tail[length -1])
            {
               
                // v[i] extends the largest subsequence
                tail[length++] = v[i];
            }
            else
            {
               
                // v[i] will extend a subsequence and
                // discard older subsequence
 
                // find the largest value just smaller than
                // v[i] in tail
 
                // to find that value do binary search for
                // the v[i] in the range from begin to 0 +
                // length
                int idx =  lowerBound(v, 1, v.GetLength(0), v[i]);
 
                // binarySearch in C# returns negative
                // value if searched element is not found in
                // array
 
                // this negative value stores the
                // appropriate place where the element is
                // supposed to be stored
                if (idx < 0)
                    idx = -1 * idx -1;
 
                // replacing the existing subsequence with
                // new end value
                tail[idx] = v[i];
            }
        }
        return length;
    }
 
    // Driver program to test above function
    public static void Main(String[] args)
    {
        int []v = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
         
        Console.WriteLine(
            "Length of longest Increasing Subsequence is "
            + (longestIncreasingSubsequenceLength(v)+1));
    }
}
 
// This code is contributed by umadevi9616


Javascript




<script>
      
function lowerBound(a , low , high , element){
    while(low < high){
        var middle = low + (high - low)/2;
        if(element > a[middle])
            low = middle + 1;
        else
            high = middle;
    }
    return low;
    function longestIncreasingSubsequenceLength(v)
    {
        if (v.length == 0) // boundary case
            return 0;
 
        var tail = Array(v.length).fill(0);
        var length = 1; // always points empty slot in tail
        tail[0] = v[0];
 
        for (i = 1; i < v.length; i++) {
 
            if (v[i] > tail[length -1])
            {
               
                // v[i] extends the largest subsequence
                tail[length++] = v[i];
            }
            else
            {
               
                // v[i] will extend a subsequence and
                // discard older subsequence
 
                // find the largest value just smaller than
                // v[i] in tail
 
                // to find that value do binary search for
                // the v[i] in the range from begin to 0 +
                // length
                var idx =  lowerBound(v, 1, v.length, v[i]);
 
                // binarySearch in C# returns negative
                // value if searched element is not found in
                // array
 
                // this negative value stores the
                // appropriate place where the element is
                // supposed to be stored
                if (idx < 0)
                    idx = -1 * idx -1;
 
                // replacing the existing subsequence with
                // new end value
                tail[idx] = v[i];
            }
        }
        return length;
    }
 
    // Driver program to test above function
 
        var v = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ];
         
        document.write(
            "Length of longest Increasing Subsequence is "
            + (longestIncreasingSubsequenceLength(v)+1));
 
// This code is contributed by gauravrajput1
</script>


Output

Length of Longest Increasing Subsequence is 6

Time Complexity: O(nlogn)
Auxiliary Space: O(n)
Venki. Please write comments if you find anything incorrect, or if you want to share more information about the topic discussed above.
 


My Personal Notes arrow_drop_up
Last Updated : 24 Apr, 2023
Like Article
Save Article
Similar Reads
Related Tutorials