Open In App

Longest Increasing Subsequence Size (N log N)

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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}

Longest Increasing Subsequence using Binary Search:

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 nums from left to right.

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

  • If the number is greater than the last element of the last bucket (i.e., the largest element in the current subsequence), we append the number to the end of the list. This indicates that we have found a longer subsequence.
  • Otherwise, we perform a binary search on the list of buckets to find the smallest element that is greater than or equal to the current number. This step helps us maintain the property of increasing elements in the buckets.
  • Once we find the position to update, we replace that element with the current number. This keeps the buckets sorted and ensures that we have the potential for a longer subsequence in the future.

Below is the implementation of the above approach:

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<int>& nums)
{
 
    // Binary search approach
    int n = nums.size();
    vector<int> ans;
 
    // Initialize the answer vector with the
    // first element of nums
    ans.push_back(nums[0]);
 
    for (int i = 1; i < n; i++) {
        if (nums[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(nums[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(),
                                  nums[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] = nums[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<int> nums = { 10, 22, 9, 33, 21, 50, 41, 60 };
    // Function call
    printf("Length of LIS is %d\n", lengthOfLIS(nums));
    return 0;
}


Java




import java.util.*;
 
public class GFG {
    static int lengthOfLIS(int[] nums) {
        // Binary search approach
        int n = nums.length;
        List<Integer> ans = new ArrayList<>();
 
        // Initialize the answer list with the
        // first element of nums
        ans.add(nums[0]);
 
        for (int i = 1; i < n; i++) {
            if (nums[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(nums[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, nums[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, nums[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[] nums = {10, 22, 9, 33, 21, 50, 41, 60};
        // Function call
        System.out.println("Length of LIS is " + lengthOfLIS(nums));
    }
}


Python3




def lengthOfLIS(nums):
    # Binary search approach
    n = len(nums)
    ans = []
 
    # Initialize the answer list with the
    # first element of nums
    ans.append(nums[0])
 
    for i in range(1, n):
        if nums[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(nums[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] < nums[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] = nums[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__":
    nums = [10, 22, 9, 33, 21, 50, 41, 60]
    # Function call
    print("Length of LIS is", lengthOfLIS(nums))


C#




using System;
using System.Collections.Generic;
 
class GFG
{
    static int LengthOfLIS(List<int> nums)
    {
        // Binary search approach
        int n = nums.Count;
        List<int> ans = new List<int>();
 
        // Initialize the answer list with the
        // first element of nums
        ans.Add(nums[0]);
 
        for (int i = 1; i < n; i++)
        {
            if (nums[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(nums[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(nums[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] = nums[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> nums = new List<int> { 10, 22, 9, 33, 21, 50, 41, 60 };
        // Function call
        Console.WriteLine("Length of LIS is " + LengthOfLIS(nums));
    }
}


Javascript




function lengthOfLIS(nums) {
    // Binary search approach
    const n = nums.length;
    const ans = [];
 
    // Initialize the answer array with the first element of nums
    ans.push(nums[0]);
 
    for (let i = 1; i < n; i++) {
        if (nums[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(nums[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 >= nums[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] = nums[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 nums = [10, 22, 9, 33, 21, 50, 41, 60];
// Function call
console.log("Length of LIS is " + lengthOfLIS(nums));


Output

Length of LIS is 5

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



Last Updated : 20 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads