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++ 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 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 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# 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 |
<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> |
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++ 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 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. |
# 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))
|
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));
}
} |
// 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)); |
4
Time Complexity: O(n^2) where n is the length of the sequence
Auxiliary Space: O(n)