Open In App

Minimum number of increasing subsequences

Last Updated : 23 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of integers of size N, you have to divide it into the minimum number of “strictly increasing subsequences” 
For example: let the sequence be {1, 3, 2, 4}, then the answer would be 2. In this case, the first increasing sequence would be {1, 3, 4} and the second would be {2}.
Examples:

Input : arr[] = {1, 3, 2, 4} 
Output:
There are two increasing subsequences {1, 3, 4} and {2}

Input : arr[] = {4, 3, 2, 1} 
Output : 4

Input : arr[] = {1, 2, 3, 4} 
Output : 1

Input : arr[] = {1, 6, 2, 4, 3} 
Output : 3

Approach: To solve the problem, follow the below idea:

If we focus on the examples, we can see that the Minimum number of increasing subsequences equals to the length of longest decreasing subsequence where each element from the longest decreasing subsequence belongs to a single increasing subsequence, so it can be found in N*Log(N) time complexity in the same way as longest increasing subsequence by multiplying all the elements with -1. 

Step-by-step approach:

  • Initialize a dp[] array of length N.
  • Multiply all the elements of the array with -1, so that our problem now gets reduced to finding the length of longest increasing subsequence.
  • Return the length of longest increasing subsequence using Binary Search.

Below is the implementation of above approach:

C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

// To search for correct position of num in array dp
int search(vector<int> dp, int num)
{

    // Initialise low,high and ans
    int low = 0, high = dp.size() - 1;
    int ans = -1;
    while (low <= high) {

        // Get mid
        int mid = low + ((high - low) / 2);

        // If mid element is >=num search for left half
        if (dp[mid] >= num) {
            ans = mid;
            high = mid - 1;
        }

        else
            low = mid + 1;
    }
    return ans;
}

int longestIncreasingSubsequence(vector<int> arr, int N)
{
    vector<int> ans;

    // Initialize the answer vector with the
    // first element of nums
    ans.push_back(arr[0]);

    for (int i = 1; i < N; i++) {
        if (arr[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(arr[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(),
                                  arr[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] = arr[i];
        }
    }

    // The length of the answer vector
    // represents the length of the
    // longest increasing subsequence.
    return ans.size();
}

// Driver code
int main()
{
    int N = 5;
    vector<int> arr{1, 6, 2, 4, 3};
    for (int i = 0; i < N; i++)
        arr[i] = -arr[i];

    cout << longestIncreasingSubsequence(arr, N) << endl;
    return 0;
}

// This code is contributed by shinjanpatra
Java
import java.util.*;

class Main {
    // To search for correct position of num in array dp
    static int search(ArrayList<Integer> dp, int num) {
        // Initialise low, high and ans
        int low = 0, high = dp.size() - 1;
        int ans = -1;
        while (low <= high) {
            // Get mid
            int mid = low + ((high - low) / 2);
            // If mid element is >=num search for left half
            if (dp.get(mid) >= num) {
                ans = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return ans;
    }

    static int longestIncreasingSubsequence(ArrayList<Integer> arr, int N) {
        ArrayList<Integer> ans = new ArrayList<>();
        // Initialize the answer ArrayList with the first element of arr
        ans.add(arr.get(0));
        for (int i = 1; i < N; i++) {
            if (arr.get(i) > ans.get(ans.size() - 1)) {
                // If the current number is greater than the last element of the answer ArrayList,
                // it means we have found a longer increasing subsequence.
                // Hence, we append the current number to the answer ArrayList.
                ans.add(arr.get(i));
            } else {
                // If the current number is not greater than the last element of the answer ArrayList,
                // we perform a binary search to find the smallest element in the answer ArrayList
                // that is greater than or equal to the current number.
                int low = Collections.binarySearch(ans, arr.get(i));
                if (low < 0) {
                    low = -(low + 1);
                }
                // We update the element at the found position with the current number.
                // By doing this, we are maintaining a sorted order in the answer ArrayList.
                ans.set(low, arr.get(i));
            }
        }
        // The size of the answer ArrayList represents the length of the longest increasing subsequence.
        return ans.size();
    }

    // Driver code
    public static void main(String[] args) {
        int N = 5;
        ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(1, 6, 2, 4, 3));
        for (int i = 0; i < N; i++) {
            arr.set(i, -arr.get(i));
        }
        System.out.println(longestIncreasingSubsequence(arr, N));
    }
}
C#
using System;
using System.Collections.Generic;

public class LIS
{
    // To search for the correct position of num in the array dp
    static int Search(List<int> dp, int num)
    {
        // Initialize low, high, and ans
        int low = 0, high = dp.Count - 1;
        int ans = -1;
        while (low <= high)
        {
            // Get mid
            int mid = low + ((high - low) / 2);

            // If mid element is >= num search for left half
            if (dp[mid] >= num)
            {
                ans = mid;
                high = mid - 1;
            }
            else
                low = mid + 1;
        }
        return ans;
    }

    static int LongestIncreasingSubsequence(List<int> arr, int N)
    {
        List<int> ans = new List<int>();

        // Initialize the answer list with the first element of nums
        ans.Add(arr[0]);

        for (int i = 1; i < N; i++)
        {
            if (arr[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(arr[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 index = ans.BinarySearch(arr[i]);
                if (index < 0)
                    index = ~index; // If not found, BinarySearch returns bitwise complement of the index to insert

                // 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[index] = arr[i];
            }
        }

        // The length of the answer list represents the length of the
        // longest increasing subsequence.
        return ans.Count;
    }

    // Driver code
    public static void Main(string[] args)
    {
        int N = 5;
        List<int> arr = new List<int> { 1, 6, 2, 4, 3 };
        for (int i = 0; i < N; i++)
            arr[i] = -arr[i]; // Negating the array elements to find the longest decreasing subsequence

        Console.WriteLine(LongestIncreasingSubsequence(arr, N));
    }
}
Javascript
// Function to search for the correct position of num in the array dp using binary search
function search(dp, num) {
    let low = 0, high = dp.length - 1;
    let ans = -1;
    while (low <= high) {
        let mid = low + Math.floor((high - low) / 2);
        if (dp[mid] >= num) {
            // If mid element is >= num, search for the left half
            ans = mid;
            high = mid - 1;
        } else {
            // If mid element is < num, search for the right half
            low = mid + 1;
        }
    }
    return ans;
}

// Function to find the length of the longest increasing subsequence
function longestIncreasingSubsequence(arr, N) {
    let ans = [];

    // Initialize the answer array with the first element of arr
    ans.push(arr[0]);

    for (let i = 1; i < N; i++) {
        if (arr[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 append the current number to the answer array.
            ans.push(arr[i]);
        } else {
            // If the current number is not greater than the last element of the answer array,
            // perform a binary search to find the smallest element in the answer array
            // that is greater than or equal to the current number.
            let low = ans.findIndex(el => el >= arr[i]);
            if (low < 0) {
                low = -(low + 1);
            }
            // 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] = arr[i];
        }
    }

    // The length of the answer array represents the length of the longest increasing subsequence.
    return ans.length;
}

// Driver code
const N = 5;
let arr = [1, 6, 2, 4, 3];
arr = arr.map(num => -num); // Negating elements of the array
console.log(longestIncreasingSubsequence(arr, N));
Python3
import bisect
def longestIncreasingSubsequence(arr):
    ans = []

    # Initialize the answer list with the
    # first element of arr
    ans.append(arr[0])

    # Traverse through the array starting from
    # the second element
    for i in range(1, len(arr)):
        if arr[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(arr[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 bisect.bisect_left() function
            # returns the index where the current
            # number should be inserted in order
            # to maintain the sorted order.
            low = bisect.bisect_left(ans, arr[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.
            ans[low] = arr[i]

    # The length of the answer list
    # represents the length of the
    # longest increasing subsequence.
    return len(ans)


# Driver code
if __name__ == "__main__":
    arr = [-1, -6, -2, -4, -3]
    print(longestIncreasingSubsequence(arr))

Output
3







Time complexity: O(N * log(N))
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads