Open In App

Longest Increasing Subsequence using Longest Common Subsequence Algorithm

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

Given an array arr[] of N integers, the task is to find and print the Longest Increasing Subsequence.
Examples: 

Input: arr[] = {12, 34, 1, 5, 40, 80} 
Output:
{12, 34, 40, 80} and {1, 5, 40, 80} are the 
longest increasing subsequences.
Input: arr[] = {10, 22, 9, 33, 21, 50, 41, 60, 80} 
Output:

Prerequisite: LCS, LIS
Approach: The longest increasing subsequence of any sequence is the subsequence of the sorted sequence of itself. It can be solved using a Dynamic Programming approach. The approach is the same as the classical LCS problem but instead of the second sequence, given sequence is taken again in its sorted form.
Note:  We should remove all duplicates otherwise it might give wrong result. For example in {1, 1, 1} we know the longest increasing subsequence(a1 < a2 < … ak) is of length 1, but if we try out this example in LIS using LCS method we would get 3 (because it finds the longest common subsequence). 
Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
//function to return size of array without duplicates
int removeDuplicates(vector<int> &arr)
{
    int k = 0;
    for (int i = 1; i < arr.size(); i++)
    {
        if (arr[i] != arr[k]) {
            arr[++k] = arr[i];
        }
    }
    return k + 1;
}
// Function to return the size of the
// longest increasing subsequence
int LISusingLCS(vector<int>& seq)
{
    int n = seq.size();
 
    // Create an 2D array of integer
    // for tabulation
    vector<vector<int> > L(n + 1, vector<int>(n + 1));
 
    // Take the second sequence as the sorted
    // sequence of the given sequence
    vector<int> sortedseq(seq);
 
    sort(sortedseq.begin(), sortedseq.end());
    //remove duplicates
      int m = removeDuplicates(sortedseq)
    // Classical Dynamic Programming algorithm
    // for Longest Common Subsequence
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            if (i == 0 || j == 0)
                L[i][j] = 0;
 
            else if (seq[i - 1] == sortedseq[j - 1])
                L[i][j] = L[i - 1][j - 1] + 1;
 
            else
                L[i][j] = max(L[i - 1][j], L[i][j - 1]);
        }
    }
 
    // Return the ans
    return L[n][m];
}
 
// Driver code
int main()
{
 
    vector<int> sequence{ 12, 34, 1, 5, 40, 80 };
 
    cout << LISusingLCS(sequence) << endl;
 
    return 0;
}


Java




//Java implementation of above approach
import java.util.*;
 
class GFG
{
     
// Function to return the size of the
// longest increasing subsequence
static int LISusingLCS(Vector<Integer> seq)
{
    int n = seq.size();
 
    // Create an 2D array of integer
    // for tabulation
    int L[][] = new int [n + 1][n + 1];
 
    // Take the second sequence as the sorted
    // sequence of the given sequence
    Vector<Integer> sortedseq = new Vector<Integer>(seq);
 
    Collections.sort(sortedseq);
 
    // Classical Dynamic Programming algorithm
    // for Longest Common Subsequence
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j <= n; j++)
        {
            if (i == 0 || j == 0)
                L[i][j] = 0;
 
            else if (seq.get(i - 1) == sortedseq.get(j - 1))
                L[i][j] = L[i - 1][j - 1] + 1;
 
            else
                L[i][j] = Math.max(L[i - 1][j],
                                   L[i][j - 1]);
        }
    }
 
    // Return the ans
    return L[n][n];
}
 
// Driver code
public static void main(String args[])
{
    Vector<Integer> sequence = new Vector<Integer>();
    sequence.add(12);
    sequence.add(34);
    sequence.add(1);
    sequence.add(5);
    sequence.add(40);
    sequence.add(80);
 
    System.out.println(LISusingLCS(sequence));
}
}
 
// This code is contributed by Arnab Kundu


Python3




# Python3 implementation of the approach
 
# Function to return the size of the
# longest increasing subsequence
def LISusingLCS(seq):
    n = len(seq)
 
    # Create an 2D array of integer
    # for tabulation
    L = [[0 for i in range(n + 1)]
            for i in range(n + 1)]
     
    # Take the second sequence as the sorted
    # sequence of the given sequence
    sortedseq = sorted(seq)
 
    # Classical Dynamic Programming algorithm
    # for Longest Common Subsequence
    for i in range(n + 1):
        for j in range(n + 1):
            if (i == 0 or j == 0):
                L[i][j] = 0
 
            elif (seq[i - 1] == sortedseq[j - 1]):
                L[i][j] = L[i - 1][j - 1] + 1
 
            else:
                L[i][j] = max(L[i - 1][j],
                              L[i][j - 1])
 
    # Return the ans
    return L[n][n]
 
# Driver code
sequence = [12, 34, 1, 5, 40, 80]
 
print(LISusingLCS(sequence))
 
# This code is contributed by mohit kumar


C#




// C# implementation of above approach
using System;
using System.Collections.Generic;
 
class GFG
{
     
// Function to return the size of the
// longest increasing subsequence
static int LISusingLCS(List<int> seq)
{
    int n = seq.Count;
 
    // Create an 2D array of integer
    // for tabulation
    int [,]L = new int [n + 1, n + 1];
 
    // Take the second sequence as the sorted
    // sequence of the given sequence
    List<int> sortedseq = new List<int>(seq);
 
    sortedseq.Sort();
 
    // Classical Dynamic Programming algorithm
    // for longest Common Subsequence
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j <= n; j++)
        {
            if (i == 0 || j == 0)
                L[i, j] = 0;
 
            else if (seq[i - 1] == sortedseq[j - 1])
                L[i, j] = L[i - 1, j - 1] + 1;
 
            else
                L[i,j] = Math.Max(L[i - 1, j],
                                L[i, j - 1]);
        }
    }
 
    // Return the ans
    return L[n, n];
}
 
// Driver code
public static void Main(String []args)
{
    List<int> sequence = new List<int>();
    sequence.Add(12);
    sequence.Add(34);
    sequence.Add(1);
    sequence.Add(5);
    sequence.Add(40);
    sequence.Add(80);
 
    Console.WriteLine(LISusingLCS(sequence));
}
}
 
// This code is contributed by 29AjayKumar


Javascript




<script>
//Javascript implementation of above approach
 
// Function to return the size of the
// longest increasing subsequence
function LISusingLCS(seq)
{
    let n = seq.length;
  
    // Create an 2D array of integer
    // for tabulation
    let L = new Array(n + 1);
    for(let i = 0; i < (n + 1); i++)
    {
        L[i] = new Array(n + 1);
        for(let j = 0; j < (n + 1); j++)
        {
            L[i][j] = 0;
        }
    }
  
    // Take the second sequence as the sorted
    // sequence of the given sequence
    let sortedseq =[...seq];
  
    sortedseq.sort(function(a,b){return a-b;});
    // Classical Dynamic Programming algorithm
    // for Longest Common Subsequence
    for (let i = 0; i <= n; i++)
    {
        for (let j = 0; j <= n; j++)
        {
            if (i == 0 || j == 0)
                L[i][j] = 0;
  
            else if (seq[i - 1] == sortedseq[j - 1])
                L[i][j] = L[i - 1][j - 1] + 1;
  
            else
                L[i][j] = Math.max(L[i - 1][j],
                                   L[i][j - 1]);
        }
    }
  
    // Return the ans
    return L[n][n];
}
 
// Driver code
let sequence = [12, 34, 1, 5, 40, 80];
document.write(LISusingLCS(sequence));
 
// This code is contributed by patel2127
</script>


Output: 

4

 

Time Complexity: O(n2) where n is the length of the sequence
Auxiliary Space: O(n2)
 

Efficient approach: Space Optimization

In previous approach the current value i.e. L[i][j] is depend no the current and previous row values. So to optimize the space complexity we can only keep track of the current and previous values of L[j] instead of the entire 2D array. This reduces the space complexity to O(n) instead of O(n^2).

Implementation Steps:

  • Create a vector L of size n+1 to store the values of the Longest Increasing Subsequence.
  • Create a copy of the original sequence called sortedseq and sort it in descending order and remove duplicates.
  • Use a nested for-loop, where the outer loop iterates through i from 1 to n and the inner loop iterates through j from 1 to m.
  • Use two variables prev and curr to store the left and top values of the current cell L[i][j].
  • If seq[i-1] and sortedseq[j-1] are equal, update L[j] with prev+1. else update L[j] with max(L[j], L[j-1]).
  • Update prev to curr at the end of each inner loop iteration.
  • Return the value at L[m] as the Longest Increasing Subsequence.

Implementation:

C++




// C++ implementation of the approach
 
#include <bits/stdc++.h>
using namespace std;
 
//function to return size of array without duplicates
int removeDuplicates(vector<int> &arr)
{
    int k = 0;
    for (int i = 1; i < arr.size(); i++)
    {
        if (arr[i] != arr[k]) {
            arr[++k] = arr[i];
        }
    }
    return k + 1;
}
 
// Function to return the size of the
// longest increasing subsequence
int LISusingLCS(vector<int>& seq)
{
    int n = seq.size();
   
      // Create an veector of integer
      // to store values
    vector<int> L(n + 1);
     
      // Take the second sequence as the sorted
    // sequence of the given sequence
    vector<int> sortedseq(seq);
   
   
    sort(sortedseq.begin(), sortedseq.end());
   
      //remove duplicates
    int m = removeDuplicates(sortedseq);
     
      // Classical Dynamic Programming algorithm
    // for Longest Common Subsequence
    for (int i = 1; i <= n; i++) {
        int prev = 0;
        for (int j = 1; j <= m; j++) {
            int curr = L[j];
            if (seq[i - 1] == sortedseq[j - 1])
                L[j] = prev + 1;
            else
                L[j] = max(L[j], L[j - 1]);
            prev = curr;
        }
    }
     
      // Return the answer
    return L[m];
}
     
// Driver code
int main()
{
    vector<int> sequence{ 12, 34, 1, 5, 40, 80 };
      // function call
    cout << LISusingLCS(sequence) << endl;
    return 0;
}


Java




// Java code addition
import java.io.*;
import java.util.*;
 
// Function to return size of array without duplicates
class GFG{
  public static int removeDuplicates(int[] arr) {
    int k = 0;
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] != arr[k]) {
        arr[++k] = arr[i];
      }
    }
    return k + 1;
  }
 
  // Function to return the size of the longest increasing subsequence
  public static int LISusingLCS(int[] seq) {
    int n = seq.length;
 
    // Create an array of integer to store values
    int[] L = new int[n + 1];
 
    // Take the second sequence as the sorted sequence of the given sequence
    int[] sortedseq = seq.clone();
 
    Arrays.sort(sortedseq);
 
    // Remove duplicates
    int m = removeDuplicates(sortedseq);
 
    // Classical Dynamic Programming algorithm for Longest Common Subsequence
    for (int i = 1; i <= n; i++) {
      int prev = 0;
      for (int j = 1; j <= m; j++) {
        int curr = L[j];
        if (seq[i - 1] == sortedseq[j - 1])
          L[j] = prev + 1;
        else
          L[j] = Math.max(L[j], L[j - 1]);
        prev = curr;
      }
    }
 
    // Return the answer
    return L[m];
  }
 
  // Driver code
  public static void main(String[] args) {
    int[] sequence = {12, 34, 1, 5, 40, 80};
    // Function call
    System.out.println(LISusingLCS(sequence));
  }
 
}
 
// The code is contributed by Nidhi goel.


Python3




# Python implementation of the approach
 
# function to return size of array without duplicates
def removeDuplicates(arr):
    k = 0
    for i in range(1, len(arr)):
        if arr[i] != arr[k]:
            k += 1
            arr[k] = arr[i]
    return k + 1
 
# Function to return the size of the
# longest increasing subsequence
def LISusingLCS(seq):
    n = len(seq)
   
    # Create a list of integer to store values
    L = [0] * (n + 1)
 
    # Take the second sequence as the sorted
    # sequence of the given sequence
    sortedseq = sorted(seq)
 
    # remove duplicates
    m = removeDuplicates(sortedseq)
 
    # Classical Dynamic Programming algorithm
    # for Longest Common Subsequence
    for i in range(1, n + 1):
        prev = 0
        for j in range(1, m + 1):
            curr = L[j]
            if seq[i - 1] == sortedseq[j - 1]:
                L[j] = prev + 1
            else:
                L[j] = max(L[j], L[j - 1])
            prev = curr
 
    # Return the answer
    return L[m]
     
# Driver code
if __name__ == '__main__':
    sequence = [12, 34, 1, 5, 40, 80]
     
    # function call
    print(LISusingLCS(sequence))


C#




using System;
using System.Linq;
 
// Function to return size of array without duplicates
class GFG {
    public static int RemoveDuplicates(int[] arr)
    {
        int k = 0;
        for (int i = 1; i < arr.Length; i++) {
            if (arr[i] != arr[k]) {
                arr[++k] = arr[i];
            }
        }
        return k + 1;
    }
 
    // Function to return the size of the longest increasing
    // subsequence
    public static int LISusingLCS(int[] seq)
    {
        int n = seq.Length;
 
        // Create an array of integer to store values
        int[] L = new int[n + 1];
 
        // Take the second sequence as the sorted sequence
        // of the given sequence
        int[] sortedseq = seq.Clone() as int[];
 
        Array.Sort(sortedseq);
 
        // Remove duplicates
        int m = RemoveDuplicates(sortedseq);
 
        // Classical Dynamic Programming algorithm for
        // Longest Common Subsequence
        for (int i = 1; i <= n; i++) {
            int prev = 0;
            for (int j = 1; j <= m; j++) {
                int curr = L[j];
                if (seq[i - 1] == sortedseq[j - 1])
                    L[j] = prev + 1;
                else
                    L[j] = Math.Max(L[j], L[j - 1]);
                prev = curr;
            }
        }
 
        // Return the answer
        return L[m];
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        int[] sequence = { 12, 34, 1, 5, 40, 80 };
        // Function call
        Console.WriteLine(LISusingLCS(sequence));
    }
}


Javascript




// Function to return size of array without duplicates
function removeDuplicates(arr) {
    let k = 0;
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] != arr[k]) {
            arr[++k] = arr[i];
        }
    }
    return k + 1;
}
 
// Function to return the size of the longest increasing subsequence
function LISusingLCS(seq) {
    let n = seq.length;
 
    // Create an array of integer to store values
    let L = new Array(n + 1).fill(0);
 
    // Take the second sequence as the sorted sequence of the given sequence
    let sortedseq = [...seq];
 
    sortedseq.sort((a, b) => a - b);
 
    // Remove duplicates
    let m = removeDuplicates(sortedseq);
 
    // Classical Dynamic Programming algorithm for Longest Common Subsequence
    for (let i = 1; i <= n; i++) {
        let prev = 0;
        for (let j = 1; j <= m; j++) {
            let curr = L[j];
            if (seq[i - 1] == sortedseq[j - 1])
                L[j] = prev + 1;
            else
                L[j] = Math.max(L[j], L[j - 1]);
            prev = curr;
        }
    }
 
    // Return the answer
    return L[m];
}
 
// Driver code
let sequence = [12, 34, 1, 5, 40, 80];
// Function call
console.log(LISusingLCS(sequence));


Output

4

Time Complexity: O(n^2) where n is the length of the sequence
Auxiliary Space: O(n)



Last Updated : 26 Apr, 2023
Like Article
Save Article
Share your thoughts in the comments
Similar Reads