Open In App

Printing Longest Increasing Subsequence (LIS)

Last Updated : 21 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order. Here we need to print a LIS as well. In case there are multiple LIS (as shown in the example 2 below), we need to print the LIS that has lexicographic ally smallest index order.

Examples:  

Input:  [10, 20, 3, 40]
Output : 10 20 40
Explanation: The length of LIS is 3 and the LIS is [10, 20, 40]

Input:  [10, 22, 9, 33, 21, 50, 41, 60, 80]
Output : 10 22 33 50 60 80
Explanation: There are multiple LIS of length 6, examples [10, 22, 33, 50, 60, 80] and [10 22 33 41 60 80]. The first one has lexicographic smallest order.

Naive Solution:

Let arr[0..n-1] be the input array. We define a vector L such that L[i] is itself is a vector that stores LIS of arr that ends with arr[i]. For example, for array [3, 2, 6, 4, 5, 1], 

L[0]: 3
L[1]: 2
L[2]: 2 6
L[3]: 2 4
L[4]: 2 4 5
L[5]: 1

Therefore, for index i, L[i] can be recursively written as – 

L[0] = {arr[O]}
L[i] = {Max(L[j])} + arr[i]
where j < i and arr[j] < arr[i] and if there is no such j then L[i] = arr[i]

Below is the implementation of the above idea – 

C++
#include <iostream>
#include <vector>
using namespace std;

// Function to construct and print Longest 
// Increasing Subsequence
vector<int> getLOS(vector<int>& arr, int n)
{
    // L[i] - The longest increasing 
    // sub-sequence ends with arr[i]
    vector<vector<int>> L(n);

    // L[0] is equal to arr[0]
    L[0].push_back(arr[0]);

    // Start from index 1
    for (int i = 1; i < n; i++)
    {
        int lis = 1;

        // Do for every prev less than i
        for (int prev = 0; prev < i; prev++)
        {
            /* L[i] = {Max(L[prev])} + arr[i]
               where prev < i and arr[prev] < arr[i] */
            if ((arr[i] > arr[prev]) && 
                (lis < L[prev].size() + 1)) {
              
                // Copy the vector of prev and update lis of i
                L[i] = L[prev];
                lis = L[prev].size() + 1;
            }
        }

        // L[i] ends with arr[i]
        L[i].push_back(arr[i]);
    }

    // L[i] now stores increasing sub-sequence 
    // of arr[0..i] that ends with arr[i]
    vector<int> max = L[0];

    // LIS will be max of all increasing 
    // sub-sequences of arr
    for (vector<int> x : L)
        if (x.size() > max.size())
            max = x;
    return max;
}

// Driver function
int main()
{
    vector<int> arr = { 3, 2, 6, 4, 5, 1 };
    int n = arr.size();
    vector<int> res = getLOS(arr, n);
    for (int x : res)
        cout << x << " ";
    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class GfG {

    // Utility function to print LIS
    static void printLIS(List<Integer> arr) {
        for (int x : arr) {
            System.out.print(x + " ");
        }
        System.out.println();
    }

    // Function to construct and print Longest
    // Increasing Subsequence
    static void constructPrintLIS(int[] arr, int n) {
      
        // L[i] - The longest increasing sub-sequence 
        // ends with arr[i]
        List<List<Integer>> L = new ArrayList<>();

        // Initialize the lists
        for (int i = 0; i < n; i++) {
            L.add(new ArrayList<>());
        }

        // L[0] is equal to arr[0]
        L.get(0).add(arr[0]);

        // Start from index 1
        for (int i = 1; i < n; i++) {
            int lis = 1;

            // Do for every prev less than i
            for (int prev = 0; prev < i; prev++) {
              
                /* L[i] = {Max(L[prev])} + arr[i]
                   where prev < i and arr[prev] < arr[i] */
                if ((arr[i] > arr[prev]) && 
                    (lis < L.get(prev).size() + 1)) {
                  
                    // Copy the list of prev and update lis of i
                    L.set(i, new ArrayList<>(L.get(prev)));
                    lis = L.get(prev).size() + 1;
                }
            }

            // L[i] ends with arr[i]
            L.get(i).add(arr[i]);
        }

        // L[i] now stores increasing sub-sequence
        // of arr[0..i] that ends with arr[i]
        List<Integer> max = L.get(0);

        // LIS will be max of all increasing
        // sub-sequences of arr
        for (List<Integer> x : L) {
            if (x.size() > max.size()) {
                max = x;
            }
        }

        // max will contain LIS
        printLIS(max);
    }

    // Driver function
    public static void main(String[] args) {
        int[] arr = {3, 2, 6, 4, 5, 1};
        int n = arr.length;
        constructPrintLIS(arr, n);
    }
}
Python
def construct_print_lis(arr):
    n = len(arr)
    
    # L[i] - The longest increasing sub-sequence ends with arr[i]
    L = [[] for _ in range(n)]

    # L[0] is equal to arr[0]
    L[0].append(arr[0])

    # Start from index 1
    for i in range(1, n):
        lis = 1
        
        # Do for every prev less than i
        for prev in range(i):
            if arr[i] > arr[prev] and lis < len(L[prev]) + 1:
              
                # Copy the list of prev and update lis of i
                L[i] = L[prev][:]
                lis = len(L[prev]) + 1

        # L[i] ends with arr[i]
        L[i].append(arr[i])

    # L[i] now stores increasing sub-sequence
    # of arr[0..i] that ends with arr[i]
    max_lis = L[0]

    # LIS will be max of all increasing 
    # sub-sequences of arr
    for x in L:
        if len(x) > len(max_lis):
            max_lis = x

    # Print the longest increasing subsequence
    print(" ".join(map(str, max_lis)))

# Driver function
if __name__ == "__main__":
    arr = [3, 2, 6, 4, 5, 1]
    
    # Construct and print LIS of arr
    construct_print_lis(arr)
C#
using System;
using System.Collections.Generic;

class GfG
{
    // Utility function to print LIS
    static void PrintLIS(List<int> arr)
    {
        foreach (int x in arr)
        {
            Console.Write(x + " ");
        }
        Console.WriteLine();
    }

    // Function to construct and print
    // Longest Increasing Subsequence
    static void ConstructPrintLIS(int[] arr, int n)
    {
        // L[i] - The longest increasing 
        // sub-sequence ends with arr[i]
        List<List<int>> L = new List<List<int>>(n);

        // Initialize the lists
        for (int i = 0; i < n; i++)
        {
            L.Add(new List<int>());
        }

        // L[0] is equal to arr[0]
        L[0].Add(arr[0]);

        // Start from index 1
        for (int i = 1; i < n; i++)
        {
            int lis = 1;

            // Do for every prev less than i
            for (int prev = 0; prev < i; prev++)
            {
                /* L[i] = {Max(L[prev])} + arr[i]
                   where prev < i and arr[prev] < arr[i] */
                if (arr[i] > arr[prev] && lis < L[prev].Count + 1)
                {
                    // Copy the list of prev and update lis of i
                    L[i] = new List<int>(L[prev]);
                    lis = L[prev].Count + 1;
                }
            }

            // L[i] ends with arr[i]
            L[i].Add(arr[i]);
        }

        // L[i] now stores increasing sub-sequence of arr[0..i] that ends with arr[i]
        List<int> max = L[0];

        // LIS will be max of all increasing sub-sequences of arr
        foreach (List<int> x in L)
        {
            if (x.Count > max.Count)
            {
                max = x;
            }
        }

        // max will contain LIS
        PrintLIS(max);
    }

    // Driver function
    static void Main()
    {
        int[] arr = { 3, 2, 6, 4, 5, 1 };
        int n = arr.Length;
        ConstructPrintLIS(arr, n);
    }
}
JavaScript
// Function to construct and print Longest
// Increasing Subsequence
function constructPrintLIS(arr) {
    const n = arr.length;
    
    // L[i] - The longest increasing sub-sequence 
    // ends with arr[i]
    const L = Array.from({ length: n }, () => []);

    // L[0] is equal to arr[0]
    L[0].push(arr[0]);

    // Start from index 1
    for (let i = 1; i < n; i++) {
        let lis = 1;

        // Do for every prev less than i
        for (let prev = 0; prev < i; prev++) {
        
            if (arr[i] > arr[prev] && lis < L[prev].length + 1) {
                // Copy the list of prev and update lis of i
                L[i] = [...L[prev]];
                lis = L[prev].length + 1;
            }
        }

        // L[i] ends with arr[i]
        L[i].push(arr[i]);
    }

    // L[i] now stores increasing sub-sequence
    // of arr[0..i] that ends with arr[i]
    let maxLIS = L[0];

    // LIS will be max of all increasing 
    // sub-sequences of arr
    for (const x of L) {
        if (x.length > maxLIS.length) {
            maxLIS = x;
        }
    }

    // Print the longest increasing subsequence
    console.log(maxLIS.join(' '));
}

// Driver function
const arr = [3, 2, 6, 4, 5, 1];
constructPrintLIS(arr);

Output
3 4 5 

Time Complexity : O(n^3) (n^2 for two nested loops and n for copying another vector in a vector eg: L[i] = L[j] contributes O(n) also).

Auxiliary Space : O(n^2) as we 2d vector to store our LIS

Better Solution:

The idea is to store only indexes of previous item in the answer LIS rather than storing the whole LIS.

  1. We use an array seq[] to store indexes of previous items in LIS and used to construct the resultant sequence. Along with constructing dp[] array, we fill indexes in seq[].
  2. After filling seq[] and dp[], we find the index of the largest element in dp.
  3. Now using the index found in step 2 and seqp[, we construct the result sequence.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// Function to find the longest increasing 
// subsequence.
vector<int> getLIS(vector<int>& arr) {
   
    int n = arr.size();
  
    // Initialize dp array with 1.
    vector<int> dp(n, 1);
  
    // Initialize hash array with index values.
    // We store previous indexs in LIS here
    vector<int> seq(n);

    for (int i = 0; i < n; i++) {
      
        seq[i] = i; // Mark element itself as prev
      
        for (int prev = 0; prev < i; prev++) {
          
            // Update dp and hash values if 
            // condition satisfies.
            if (arr[prev] < arr[i] && 
                1 + dp[prev] > dp[i]) {
              
                dp[i] = 1 + dp[prev];
                seq[i] = prev;
            }
        }
    }

    // Now we find the last element 
    // in LIS using dp[]
    int ans = -1;
    int ansInd = -1;
    for (int i = 0; i < n; i++) {
        if (dp[i] > ans) {
            ans = dp[i];
            ansInd = i;
        }
    }

    // Now construct result sequence using seq[]
    // and ans_ind
    vector<int> res;
    res.push_back(arr[ansInd]);
    while (seq[ansInd] != ansInd) {
        ansInd = seq[ansInd];
        res.push_back(arr[ansInd]);
    }
    reverse(res.begin(), res.end());
    return res;
}

int main() {
    vector<int> arr = {10, 22, 9, 33, 21, 50, 41, 60};

    vector<int> res = getLIS(arr);

    cout << "The longest increasing subsequence is: ";
    for (int num : res) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

    // Function to find the longest increasing subsequence
    public static List<Integer> getLIS(int[] arr) {
        int n = arr.length;

        // Initialize dp array with 1
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
        }

        // Initialize seq array with index values (to store previous indices in LIS)
        int[] seq = new int[n];
        for (int i = 0; i < n; i++) {
            seq[i] = i;
        }

        // Compute dp and seq arrays
        for (int i = 0; i < n; i++) {
            for (int prev = 0; prev < i; prev++) {
                if (arr[prev] < arr[i] && 1 + dp[prev] > dp[i]) {
                    dp[i] = 1 + dp[prev];
                    seq[i] = prev;
                }
            }
        }

        // Find the index of the last element in the LIS
        int ans = -1;
        int ansInd = -1;
        for (int i = 0; i < n; i++) {
            if (dp[i] > ans) {
                ans = dp[i];
                ansInd = i;
            }
        }

        // Construct the result sequence using seq array
        List<Integer> res = new ArrayList<>();
        res.add(arr[ansInd]);
        while (seq[ansInd] != ansInd) {
            ansInd = seq[ansInd];
            res.add(arr[ansInd]);
        }

        // Reverse the result to get the correct order
        Collections.reverse(res);
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {10, 22, 9, 33, 21, 50, 41, 60};

        List<Integer> res = getLIS(arr);

        System.out.println("The longest increasing subsequence is: " + res);
    }
}
Python
# Function to find the longest increasing subsequence
def get_lis(arr):
    n = len(arr)

    # Initialize dp array with 1
    dp = [1] * n

    # Initialize seq array with index values (to store previous indices in LIS)
    seq = list(range(n))

    # Compute dp and seq arrays
    for i in range(n):
        for prev in range(i):
            if arr[prev] < arr[i] and 1 + dp[prev] > dp[i]:
                dp[i] = 1 + dp[prev]
                seq[i] = prev

    # Find the index of the last element in the LIS
    ans = -1
    ans_ind = -1
    for i in range(n):
        if dp[i] > ans:
            ans = dp[i]
            ans_ind = i

    # Construct the result sequence using seq array
    res = []
    res.append(arr[ans_ind])
    while seq[ans_ind] != ans_ind:
        ans_ind = seq[ans_ind]
        res.append(arr[ans_ind])

    # Reverse the result to get the correct order
    res.reverse()
    return res

if __name__ == "__main__":
    arr = [10, 22, 9, 33, 21, 50, 41, 60]

    res = get_lis(arr)

    print("The longest increasing subsequence is:", res)
C#
using System;
using System.Collections.Generic;

class Program
{
    // Function to find the longest increasing subsequence
    static List<int> GetLIS(int[] arr)
    {
        int n = arr.Length;

        // Initialize dp array with 1
        int[] dp = new int[n];
        for (int i = 0; i < n; i++)
        {
            dp[i] = 1;
        }

        // Initialize seq array with index values (to store previous indices in LIS)
        int[] seq = new int[n];
        for (int i = 0; i < n; i++)
        {
            seq[i] = i;
        }

        // Compute dp and seq arrays
        for (int i = 0; i < n; i++)
        {
            for (int prev = 0; prev < i; prev++)
            {
                if (arr[prev] < arr[i] && 1 + dp[prev] > dp[i])
                {
                    dp[i] = 1 + dp[prev];
                    seq[i] = prev;
                }
            }
        }

        // Find the index of the last element in the LIS
        int ans = -1;
        int ansInd = -1;
        for (int i = 0; i < n; i++)
        {
            if (dp[i] > ans)
            {
                ans = dp[i];
                ansInd = i;
            }
        }

        // Construct the result sequence using seq array
        List<int> res = new List<int>();
        res.Add(arr[ansInd]);
        while (seq[ansInd] != ansInd)
        {
            ansInd = seq[ansInd];
            res.Add(arr[ansInd]);
        }

        // Reverse the result to get the correct order
        res.Reverse();
        return res;
    }

    static void Main(string[] args)
    {
        int[] arr = { 10, 22, 9, 33, 21, 50, 41, 60 };

        List<int> res = GetLIS(arr);

        Console.WriteLine("The longest increasing subsequence is: " + string.Join(" ", res));
    }
}
JavaScript
// Function to find the longest increasing subsequence
function getLIS(arr) {
    const n = arr.length;

    // Initialize dp array with 1
    const dp = new Array(n).fill(1);

    // Initialize seq array with index values (to store previous indices in LIS)
    const seq = [...Array(n).keys()];

    // Compute dp and seq arrays
    for (let i = 0; i < n; i++) {
        for (let prev = 0; prev < i; prev++) {
            if (arr[prev] < arr[i] && 1 + dp[prev] > dp[i]) {
                dp[i] = 1 + dp[prev];
                seq[i] = prev;
            }
        }
    }

    // Find the index of the last element in the LIS
    let ans = -1;
    let ansInd = -1;
    for (let i = 0; i < n; i++) {
        if (dp[i] > ans) {
            ans = dp[i];
            ansInd = i;
        }
    }

    // Construct the result sequence using seq array
    const res = [];
    res.push(arr[ansInd]);
    while (seq[ansInd] !== ansInd) {
        ansInd = seq[ansInd];
        res.push(arr[ansInd]);
    }

    // Reverse the result to get the correct order
    res.reverse();
    return res;
}

const arr = [10, 22, 9, 33, 21, 50, 41, 60];

const res = getLIS(arr);

console.log("The longest increasing subsequence is:", res.join(" "));

Output
The longest increasing subsequence is: 10 22 33 50 60 

Time Complexity : O(n^2)
Auxiliary Space : O(n)

Efficient Solution:

We use the binary search idea discussed in LIS in O(n Log n) time to find the LIS in an efficient way.

Construction of Longest Monotonically Increasing Subsequence (N log N)




Next Article
Practice Tags :

Similar Reads