Open In App

Minimum concatenation required to get strictly LIS for array with repetitive elements | Set-2

Given an array A[] of size n where there can be repetitive elements in the array. We have to find the minimum concatenation required for sequence A to get strictly The Longest Increasing Subsequence. For array A[] we follow 1 based indexing.

Examples:



Input: A = {2, 1, 2, 4, 3, 5} 
Output:
Explanation: 
We can concatenate A two times as [2, 1, 2, 4, 3, 5, 2, 1, 2, 4, 3, 5] and then output for index 2, 3, 5, 10, 12 which gives sub-sequence as 1 -> 2 -> 3 -> 4 -> 5.

Input: A = {1, 3, 2, 1, 2} 
Output:
Explanation: 
We can concatenate A two times as [1, 3, 2, 1, 2, 1, 3, 2, 1, 2] and then output for index 1, 3, 7 which gives sub-sequence as 1 -> 2 -> 3. 



Approach: 
To solve the problem mentioned above the very first observation is that a strictly increasing sub-sequence will always have its length equal to the number of unique elements present in sequence A[]. Hence, the maximum length of the subsequence is equal to the count of the distinct elements. To solve the problem follow the steps given below: 

Below is the implementation of the above approach:




// C++ implementation to Find the minimum
// concatenation required to get strictly
// Longest Increasing Subsequence for the
// given array with repetitive elements
#include <bits/stdc++.h>
using namespace std;
 
int LIS(int arr[], int n)
{
    // ordered map containing value and
    // a vector containing index of
    // it's occurrences
    map<int, vector<int> > m;
 
    // Mapping index with their values
    // in ordered map
    for (int i = 0; i < n; i++)
        m[arr[i]].push_back(i);
 
    // k refers to present minimum index
    int k = n;
 
    // Stores the number of concatenation
    // required
    int ans = 0;
 
    // Iterate over map m
    for (auto it = m.begin(); it != m.end();
                                       it++) {
        // it.second refers to the vector
        // containing all corresponding
        // indexes
 
        // it.second.back refers to the
        // last element of corresponding vector
 
        if (it->second.back() < k) {
            k = it->second[0];
            ans += 1;
        }
        else
 
            // find the index of next minimum
            // element in the sequence
            k = *lower_bound(it->second.begin(),
                            it->second.end(), k);
    }
 
    // Return the final answer
    cout << ans << endl;
}
 
// Driver program
int main()
{
    int arr[] = { 1, 3, 2, 1, 2 };
 
    int n = sizeof(arr) / sizeof(arr[0]);
 
    LIS(arr, n);
 
    return 0;
}




// Java implementation to Find the minimum
// concatenation required to get strictly
// Longest Increasing Subsequence for the
// given array with repetitive elements
import java.io.*;
import java.util.*;
 
class GFG{
 
static void LIS(int arr[], int n)
{
     
    // ordered map containing value and
    // a vector containing index of
    // it's occurrences
    TreeMap<Integer,
       List<Integer>> m = new TreeMap<Integer,
                                 List<Integer>>();
     
    // Mapping index with their values
    // in ordered map
    for(int i = 0; i < n; i++)
    {
        List<Integer> indexes;
         
        if (m.containsKey(arr[i]))
        {
            indexes = m.get(arr[i]);
        }
        else
        {
            indexes = new ArrayList<Integer>();
        }
        indexes.add(i);
        m.put(arr[i], indexes);
    }
     
    // k refers to present minimum index
    int k = n;
 
    // Stores the number of concatenation
    // required
    int ans = 0;
 
    // Iterate over map m
    for(Map.Entry<Integer,
             List<Integer>> it : m.entrySet())
    {
         
        // List containing all corresponding
        // indexes
        List<Integer> indexes = it.getValue();
 
        if (indexes.get(indexes.size() - 1) < k)
        {
            k = indexes.get(0);
            ans++;
        }
        else
         
            // Find the index of next minimum
            // element in the sequence
            k = lower_bound(indexes, k);
    }
     
    // Return the final answer
    System.out.println(ans);
}
 
static int lower_bound(List<Integer> indexes,
                       int k)
{
    int low = 0, high = indexes.size() - 1;
 
    while (low < high)
    {
        int mid = (low + high) / 2;
        if (indexes.get(mid) < k)
            low = mid + 1;
        else
            high = mid;
    }
    return indexes.get(low);
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 1, 3, 2, 1, 2 };
 
    int n = arr.length;
 
    LIS(arr, n);
}
}
 
// This code is contributed by jithin




# Python3 implementation to
# Find the minimum concatenation
# required to get strictly Longest
# Increasing Subsequence for the
# given array with repetitive elements
from bisect import bisect_left
 
def LIS(arr, n):
   
    # ordered map containing
    # value and a vector containing
    # index of it's occurrences
    # <int, vector<int> > m;
    m = {}
 
    # Mapping index with their
    # values in ordered map
    for i in range(n):
        m[arr[i]] = m.get(arr[i], [])
        m[arr[i]].append(i)
 
    # k refers to present
    # minimum index
    k = n
 
    # Stores the number of
    # concatenation required
    ans = 1
 
    # Iterate over map m
    for key, value in m.items():
       
        # it.second refers to the
        # vector containing all
        # corresponding indexes
 
        # it.second.back refers
        # to the last element of
        # corresponding vector
        if (value[len(value) - 1] < k):
            k = value[0]
            ans += 1
        else:
           
            # find the index of next
            # minimum element in the
            # sequence
            k = bisect_left(value, k)
 
    # Return the final
    # answer
    print(ans)
 
# Driver code
if __name__ == '__main__':
   
    arr =  [1, 3, 2, 1, 2]
    n = len(arr)
    LIS(arr, n)
 
# This code is contributed by bgangwar59




using System;
using System.Collections.Generic;
 
class GFG {
 
  static void LIS(int[] arr, int n) {
 
    // ordered map containing value and
    // a vector containing index of
    // it's occurrences
    SortedDictionary<int, List<int>> m = new SortedDictionary<int, List<int>>();
 
    // Mapping index with their values
    // in ordered map
    for (int i = 0; i < n; i++) {
      List<int> indexes;
 
      if (m.ContainsKey(arr[i])) {
        indexes = m[arr[i]];
      }
      else {
        indexes = new List<int>();
      }
      indexes.Add(i);
      m[arr[i]] = indexes;
    }
 
    // k refers to present minimum index
    int k = n;
 
    // Stores the number of concatenation
    // required
    int ans = 0;
 
    // Iterate over map m
    foreach (KeyValuePair<int, List<int>> it in m) {
 
      // List containing all corresponding
      // indexes
      List<int> indexes = it.Value;
 
      if (indexes[indexes.Count - 1] < k) {
        k = indexes[0];
        ans++;
      }
      else
 
        // Find the index of next minimum
        // element in the sequence
        k = lower_bound(indexes, k);
    }
 
    // Return the final answer
    Console.WriteLine(ans);
  }
 
  static int lower_bound(List<int> indexes,
                         int k) {
    int low = 0, high = indexes.Count - 1;
 
    while (low < high) {
      int mid = (low + high) / 2;
      if (indexes[mid] < k)
        low = mid + 1;
      else
        high = mid;
    }
    return indexes[low];
  }
 
  // Driver code
  public static void Main() {
    int[] arr = { 1, 3, 2, 1, 2 };
    int n = arr.Length;
    LIS(arr, n);
  }
}
 
// This code is contributed by phasing17.




// JavaScript implementation to Find the minimum
// concatenation required to get strictly
// Longest Increasing Subsequence for the
// given array with repetitive elements
 
const LIS = (arr, n) => {
    // Create map to store value and index
    let m = new Map();
 
    // Map values to their indexes
    for (let i = 0; i < n; i++) {
        if (!m.has(arr[i])) {
            m.set(arr[i], [i]);
        } else {
            m.get(arr[i]).push(i);
        }
    }
 
    // k refers to present minimum index
    let k = n;
 
    // Stores the number of concatenation required
    let ans = 0;
 
    // Iterate over map m
    for (const [key, value] of m) {
        // value refers to the array containing all corresponding indexes
 
        // value[value.length - 1] refers to the last element of the corresponding array
 
        if (value[value.length - 1] < k) {
            k = value[0];
            ans += 1;
        } else {
            // find the index of next minimum element in the sequence
            k = value.find(v => v >= k);
        }
    }
 
    // Return the final answer
    console.log(ans);
};
 
// Driver program
const arr = [1, 3, 2, 1, 2];
 
const n = arr.length;
 
LIS(arr, n);

Output: 
2

 

Time complexity: O(n * log n)


Article Tags :