Longest Increasing Subsequence Size (N log N) (original) (raw)

Last Updated : 07 May, 2025

Try it on GfG Practice redirect icon

Given an array **arr[] of size **N, the task is to find the length of the Longest Increasing Subsequence (LIS) i.e., the longest possible subsequence in which the elements of the subsequence are sorted in increasing order, in O(N log N).

**Examples:

**Input: arr[] = {3, 10, 2, 1, 20}
**Output: 3
**Explanation: The longest increasing subsequence is 3, 10, 20

**Input: arr[] = {3, 2}
****Output:**1
**Explanation: The longest increasing subsequences are {3} and {2}

**Input: arr[] = {50, 3, 10, 7, 40, 80}
**Output: 4
**Explanation: The longest increasing subsequence is {3, 7, 40, 80}

The main idea of the approach is to simulate the process of finding a subsequence by maintaining a list of "buckets" where each bucket represents a valid subsequence. Initially, we start with an empty list and iterate through the input vector arr from left to right.

For each number in arr, we perform the following steps:

**Note: The resulting array only stores the length of longest increasing subsequence, and not the actual subsequence. Go through the illustration to clear this doubt.

**Illustration:

**Example: arr = [3, 4, 5, 1, 2, 3, 4] Let's see why keeping 1 (the smallest value) helps:

We use binary search to find the position where new element is to be inserted.

  1. First three elements: buckets = [3, 4, 5]
  2. arr[3] = 1 buckets = [1, 4, 5] // 1 replaces 3
  3. arr[4] = 2 buckets = [1, 2, 5] // 2 replaces 4 as it's smaller
  4. arr[5] = 3 buckets = [1, 2, 3] // 3 replaces 5
  5. arr[6] = 4 buckets = [1, 2, 3, 4] // 4 is appended as it's larger

This shows that by replacing 3 with 1, we created the opportunity to find the subsequence [1, 2, 3, 4], which is longer than our initial [3, 4, 5]. If we had kept [3, 4, 5], we wouldn't have been able to add 2 to our sequence!

The key insight is that keeping smaller values at each position:

  1. Maintains the same length information
  2. Creates more opportunities for future elements to form longer increasing subsequences

C++ `

// Binary Search Approach of Finding LIS by // reducing the problem to longest // common Subsequence #include <bits/stdc++.h> using namespace std;

int lengthOfLIS(vector& arr) {

// Binary search approach
int n = arr.size();
vector<int> ans;

// Initialize the answer vector with the
// first element of arr
ans.push_back(arr[0]);

for (int i = 1; i < n; i++) {
    if (arr[i] > ans.back()) {

        // If the current number is greater
        // than the last element of the answer
        // vector, it means we have found a
        // longer increasing subsequence.
        // Hence, we append the current number
        // to the answer vector.
        ans.push_back(arr[i]);
    }
    else {

        // If the current number is not
        // greater than the last element of
        // the answer vector, we perform
        // a binary search to find the smallest
        // element in the answer vector that
        // is greater than or equal to the
        // current number.

        // The lower_bound function returns
        // an iterator pointing to the first
        // element that is not less than
        // the current number.
        int low = lower_bound(ans.begin(), ans.end(),
                              arr[i])
                  - ans.begin();

        // We update the element at the
        // found position with the current number.
        // By doing this, we are maintaining
        // a sorted order in the answer vector.
        ans[low] = arr[i];
    }
}

// The length of the answer vector
// represents the length of the
// longest increasing subsequence.
return ans.size();

}

// Driver program to test above function int main() { vector arr = { 10, 22, 9, 33, 21, 50, 41, 60 }; printf("Length of LIS is %d\n", lengthOfLIS(arr)); return 0; }

Java

import java.util.*;

public class GFG { static int lengthOfLIS(int[] arr) { // Binary search approach int n = arr.length; List ans = new ArrayList<>();

    // Initialize the answer list with the
    // first element of arr
    ans.add(arr[0]);

    for (int i = 1; i < n; i++) {
        if (arr[i] > ans.get(ans.size() - 1)) {
            // If the current number is greater
            // than the last element of the answer
            // list, it means we have found a
            // longer increasing subsequence.
            // Hence, we append the current number
            // to the answer list.
            ans.add(arr[i]);
        } else {
            // If the current number is not
            // greater than the last element of
            // the answer list, we perform
            // a binary search to find the smallest
            // element in the answer list that
            // is greater than or equal to the
            // current number.

            // The binarySearch method returns
            // the index of the first element that is not less than
            // the current number.
            int low = Collections.binarySearch(ans, arr[i]);

            // We update the element at the
            // found position with the current number.
            // By doing this, we are maintaining
            // a sorted order in the answer list.
            if (low < 0) {
                low = -(low + 1);
            }
            ans.set(low, arr[i]);
        }
    }

    // The size of the answer list
    // represents the length of the
    // longest increasing subsequence.
    return ans.size();
}

// Driver program to test above function
public static void main(String[] args) {
    int[] arr = {10, 22, 9, 33, 21, 50, 41, 60};
    System.out.println("Length of LIS is " + lengthOfLIS(arr));
}

}

Python

def lengthOfLIS(arr): # Binary search approach n = len(arr) ans = []

# Initialize the answer list with the
# first element of arr
ans.append(arr[0])

for i in range(1, n):
    if arr[i] > ans[-1]:
        # If the current number is greater
        # than the last element of the answer
        # list, it means we have found a
        # longer increasing subsequence.
        # Hence, we append the current number
        # to the answer list.
        ans.append(arr[i])
    else:
        # If the current number is not
        # greater than the last element of
        # the answer list, we perform
        # a binary search to find the smallest
        # element in the answer list that
        # is greater than or equal to the
        # current number.
        low = 0
        high = len(ans) - 1
        while low < high:
            mid = low + (high - low) // 2
            if ans[mid] < arr[i]:
                low = mid + 1
            else:
                high = mid
        # We update the element at the
        # found position with the current number.
        # By doing this, we are maintaining
        # a sorted order in the answer list.
        ans[low] = arr[i]

# The length of the answer list
# represents the length of the
# longest increasing subsequence.
return len(ans)

Driver program to test above function

if name == "main": arr = [10, 22, 9, 33, 21, 50, 41, 60] print("Length of LIS is", lengthOfLIS(arr))

C#

using System; using System.Collections.Generic;

class GFG { static int LengthOfLIS(List arr) { // Binary search approach int n = arr.Count; List ans = new List();

    // Initialize the answer list with the
    // first element of arr
    ans.Add(arr[0]);

    for (int i = 1; i < n; i++)
    {
        if (arr[i] > ans[ans.Count - 1])
        {
            // If the current number is greater
            // than the last element of the answer
            // list, it means we have found a
            // longer increasing subsequence.
            // Hence, we append the current number
            // to the answer list.
            ans.Add(arr[i]);
        }
        else
        {
            // If the current number is not
            // greater than the last element of
            // the answer list, we perform
            // a binary search to find the smallest
            // element in the answer list that
            // is greater than or equal to the
            // current number.

            // The BinarySearch method returns
            // the index of the first element that is not less than
            // the current number.
            int low = ans.BinarySearch(arr[i]);

            // We update the element at the
            // found position with the current number.
            // By doing this, we are maintaining
            // a sorted order in the answer list.
            if (low < 0)
            {
                low = ~low;
            }
            ans[low] = arr[i];
        }
    }

    // The count of the answer list
    // represents the length of the
    // longest increasing subsequence.
    return ans.Count;
}

// Driver program to test above function
static void Main()
{
    List<int> arr = new List<int> { 10, 22, 9, 33, 21, 50, 41, 60 };
    Console.WriteLine("Length of LIS is " + LengthOfLIS(arr));
}

}

JavaScript

function lengthOfLIS(arr) { // Binary search approach const n = arr.length; const ans = [];

// Initialize the answer array with the first element of arr
ans.push(arr[0]);

for (let i = 1; i < n; i++) {
    if (arr[i] > ans[ans.length - 1]) {
        // If the current number is greater than the last element 
        // of the answer array, it means we have found a 
        // longer increasing subsequence. Hence, we push the current number
        // to the answer array.
        ans.push(arr[i]);
        
    } else {
        // If the current number is not greater than the last element of
        // the answer array, we perform a binary search to find the smallest
        // element in the answer array that is greater than or equal to the
        // current number.

        // The indexOf function returns the first index at which the current
        // number can be inserted to maintain sorted order.
        const low = ans.findIndex((el) => el >= arr[i]);

        // We update the element at the found position with the current number.
        // By doing this, we are maintaining a sorted order in the answer array.
        ans[low] = arr[i];
    }
}

// The length of the answer array represents the length of the
// longest increasing subsequence.
return ans.length;

}

// Driver program to test the function const arr = [10, 22, 9, 33, 21, 50, 41, 60]; console.log("Length of LIS is " + lengthOfLIS(arr));

`

**Time Complexity: O(n*log(n)) where n is the size of the input vector arr.
**Auxiliary Space: O(n)