Longest Increasing Subsequence using Longest Common Subsequence Algorithm

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: 4
{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: 6
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>usingnamespacestd;//function to return size of array without duplicatesintremoveDuplicates(vector<int> &arr){    intk = 0;    for(inti = 1; i < arr.size(); i++)    {        if(arr[i] != arr[k]) {            arr[++k] = arr[i];        }    }    returnk + 1;}// Function to return the size of the// longest increasing subsequenceintLISusingLCS(vector<int>& seq){    intn = 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      intm = removeDuplicates(sortedseq)    // Classical Dynamic Programming algorithm    // for Longest Common Subsequence    for(inti = 0; i <= n; i++) {        for(intj = 0; j <= m; j++) {            if(i == 0 || j == 0)                L[i][j] = 0;            elseif(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    returnL[n][m];}// Driver codeintmain(){    vector<int> sequence{ 12, 34, 1, 5, 40, 80 };    cout << LISusingLCS(sequence) << endl;    return0;} | 
Java
| //Java implementation of above approachimportjava.util.*;classGFG{    // Function to return the size of the// longest increasing subsequencestaticintLISusingLCS(Vector<Integer> seq){    intn = seq.size();    // Create an 2D array of integer    // for tabulation    intL[][] = newint[n + 1][n + 1];    // Take the second sequence as the sorted    // sequence of the given sequence    Vector<Integer> sortedseq = newVector<Integer>(seq);    Collections.sort(sortedseq);    // Classical Dynamic Programming algorithm    // for Longest Common Subsequence    for(inti = 0; i <= n; i++)     {        for(intj = 0; j <= n; j++)         {            if(i == 0|| j == 0)                L[i][j] = 0;            elseif(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    returnL[n][n];}// Driver codepublicstaticvoidmain(String args[]){    Vector<Integer> sequence = newVector<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 subsequencedefLISusingLCS(seq):    n =len(seq)    # Create an 2D array of integer    # for tabulation    L =[[0fori inrange(n +1)]             fori inrange(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    fori inrange(n +1):        forj inrange(n +1):            if(i ==0orj ==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    returnL[n][n]# Driver codesequence =[12, 34, 1, 5, 40, 80]print(LISusingLCS(sequence))# This code is contributed by mohit kumar | 
C#
| // C# implementation of above approachusingSystem;usingSystem.Collections.Generic;classGFG{    // Function to return the size of the// longest increasing subsequencestaticintLISusingLCS(List<int> seq){    intn = seq.Count;    // Create an 2D array of integer    // for tabulation    int[,]L = newint[n + 1, n + 1];    // Take the second sequence as the sorted    // sequence of the given sequence    List<int> sortedseq = newList<int>(seq);    sortedseq.Sort();    // Classical Dynamic Programming algorithm    // for longest Common Subsequence    for(inti = 0; i <= n; i++)     {        for(intj = 0; j <= n; j++)         {            if(i == 0 || j == 0)                L[i, j] = 0;            elseif(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    returnL[n, n];}// Driver codepublicstaticvoidMain(String []args){    List<int> sequence = newList<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 subsequencefunctionLISusingLCS(seq){    let n = seq.length;     // Create an 2D array of integer    // for tabulation    let L = newArray(n + 1);    for(let i = 0; i < (n + 1); i++)    {        L[i] = newArray(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){returna-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;             elseif(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    returnL[n][n];}// Driver codelet sequence = [12, 34, 1, 5, 40, 80];document.write(LISusingLCS(sequence));// This code is contributed by patel2127</script> | 
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>usingnamespacestd;//function to return size of array without duplicatesintremoveDuplicates(vector<int> &arr){    intk = 0;    for(inti = 1; i < arr.size(); i++)    {        if(arr[i] != arr[k]) {            arr[++k] = arr[i];        }    }    returnk + 1;}// Function to return the size of the// longest increasing subsequenceintLISusingLCS(vector<int>& seq){    intn = 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    intm = removeDuplicates(sortedseq);          // Classical Dynamic Programming algorithm    // for Longest Common Subsequence    for(inti = 1; i <= n; i++) {        intprev = 0;        for(intj = 1; j <= m; j++) {            intcurr = 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    returnL[m];}    // Driver codeintmain(){    vector<int> sequence{ 12, 34, 1, 5, 40, 80 };      // function call    cout << LISusingLCS(sequence) << endl;    return0;} | 
Java
| // Java code addition importjava.io.*;importjava.util.*;// Function to return size of array without duplicatesclassGFG{  publicstaticintremoveDuplicates(int[] arr) {    intk = 0;    for(inti = 1; i < arr.length; i++) {      if(arr[i] != arr[k]) {        arr[++k] = arr[i];      }    }    returnk + 1;  }  // Function to return the size of the longest increasing subsequence  publicstaticintLISusingLCS(int[] seq) {    intn = seq.length;    // Create an array of integer to store values    int[] L = newint[n + 1];    // Take the second sequence as the sorted sequence of the given sequence    int[] sortedseq = seq.clone();    Arrays.sort(sortedseq);    // Remove duplicates    intm = removeDuplicates(sortedseq);    // Classical Dynamic Programming algorithm for Longest Common Subsequence    for(inti = 1; i <= n; i++) {      intprev = 0;      for(intj = 1; j <= m; j++) {        intcurr = 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    returnL[m];  }  // Driver code  publicstaticvoidmain(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 duplicatesdefremoveDuplicates(arr):    k =0    fori inrange(1, len(arr)):        ifarr[i] !=arr[k]:            k +=1            arr[k] =arr[i]    returnk +1# Function to return the size of the# longest increasing subsequencedefLISusingLCS(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    fori inrange(1, n +1):        prev =0        forj inrange(1, m +1):            curr =L[j]            ifseq[i -1] ==sortedseq[j -1]:                L[j] =prev +1            else:                L[j] =max(L[j], L[j -1])            prev =curr    # Return the answer    returnL[m]    # Driver codeif__name__ =='__main__':    sequence =[12, 34, 1, 5, 40, 80]        # function call    print(LISusingLCS(sequence)) | 
C#
| usingSystem;usingSystem.Linq;// Function to return size of array without duplicatesclassGFG {    publicstaticintRemoveDuplicates(int[] arr)    {        intk = 0;        for(inti = 1; i < arr.Length; i++) {            if(arr[i] != arr[k]) {                arr[++k] = arr[i];            }        }        returnk + 1;    }    // Function to return the size of the longest increasing    // subsequence    publicstaticintLISusingLCS(int[] seq)    {        intn = seq.Length;        // Create an array of integer to store values        int[] L = newint[n + 1];        // Take the second sequence as the sorted sequence        // of the given sequence        int[] sortedseq = seq.Clone() asint[];        Array.Sort(sortedseq);        // Remove duplicates        intm = RemoveDuplicates(sortedseq);        // Classical Dynamic Programming algorithm for        // Longest Common Subsequence        for(inti = 1; i <= n; i++) {            intprev = 0;            for(intj = 1; j <= m; j++) {                intcurr = 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        returnL[m];    }    // Driver code    publicstaticvoidMain(string[] args)    {        int[] sequence = { 12, 34, 1, 5, 40, 80 };        // Function call        Console.WriteLine(LISusingLCS(sequence));    }} | 
Javascript
| // Function to return size of array without duplicatesfunctionremoveDuplicates(arr) {    let k = 0;    for(let i = 1; i < arr.length; i++) {        if(arr[i] != arr[k]) {            arr[++k] = arr[i];        }    }    returnk + 1;}// Function to return the size of the longest increasing subsequencefunctionLISusingLCS(seq) {    let n = seq.length;    // Create an array of integer to store values    let L = newArray(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    returnL[m];}// Driver codelet sequence = [12, 34, 1, 5, 40, 80];// Function callconsole.log(LISusingLCS(sequence)); | 
4
Time Complexity: O(n^2) where n is the length of the sequence
Auxiliary Space: O(n)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!
 
				 
					


