Smallest subarray with k distinct numbers

08 Jun, 2022
We are given an array consisting of n integers and an integer k. We need to find the minimum range in array [l, r] (both l and r are inclusive) such that there are exactly k different numbers. If such subarray doesn’t exist print “Invalid k”.Examples: 
Input : arr[] = { 1, 1, 2, 2, 3, 3, 4, 5} 
            k = 3
Output : 5 7

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

Input : arr[] = {1, 1, 2, 1, 2}
            k = 3
Output : Invalid k
Approach 1 : (Brute Force Method)
The simplest approach in this problem is, try to generate all the subarrays and check for which subarray the size is k. But there are some points we need to take care.Steps:
  1.  Pick each of the elements from the given array as the starting element [ i-th element ] of our required subarray.
  2.  In each iteration initialize an empty set to store the distinct elements of the subarray
Pick each remaining element [ i, i+1,..n – 1] from the array as the last element [ j-th element ].
Add the current element to the set.
If the set size equals k then update the results and break from the inner loop (already found k distinct elements increasing the size of the subarray has 2 possibilities either will get more distinct elements, or increase the subarray size with repeated elements which are not to be considered in the required results).
  3.  If (j == n) or j = size of the array, i.e. we have not found any desired subarray starting from i-th index and going forward we will be having fewer elements to consider.      ( For example : consider given array is 4 5 5 4 5  and k = 3, when start from 0th index we will not find any subarray of k size and j will reach end so that means we won’t get any element that can make a k = 3 size required subarray).        So, Break from the outer loop.
  4.  Print the output if found, otherwise, print “Invalid k”.
C++
Java
Python 3
C#
Javascript
// C++ program to find minimum range that// contains exactly k distinct numbers.#include <bits/stdc++.h>using namespace std; // Prints the minimum range that contains exactly// k distinct numbers.void minRange(int arr[], int n, int k){    // Starting and ending  index of resultant subarray    int start = 0, end = n;     // Selecting each element as the start index for    // subarray    for (int i = 0; i < n; i++) {        // Initialize a set to store all distinct elements        unordered_set<int> set;         // Selecting the end index for subarray        int j;        for (j = i; j < n; j++) {            set.insert(arr[j]);             /*            If set contains exactly k elements,            then check subarray[i, j] is smaller in size            than the current resultant subarray            */            if (set.size() == k) {                if (j - i < end - start) {                    start = i;                    end = j;                }                 // There are already k distinct elements                // now, no need to consider further elements                break;            }        }         // If there are no k distinct elements        // left in the array starting from index i we will        // break        if (j == n) {            break;        }    }     // If no window found then print -1    if (start == 0 && end == n)        cout << "Invalid k";     else        cout << start << " " << end;} // Driver code for above function.int main(){    int arr[] = { 1, 2, 3, 4, 5 };    int n = sizeof(arr) / sizeof(arr[0]);    int k = 3;    minRange(arr, n, k);    return 0;} // This code is contributed by Rajdeep
// Java program to find minimum// range that contains exactly// k distinct numbers.import java.util.*;import java.util.ArrayList;import java.util.HashSet; class GFG {     // Prints the minimum range    // that contains exactly k    // distinct numbers.    static void minRange(int arr[], int n, int k)    {        // start -> start index of resultant subarray        // end   -> end index of resultant subarray        int start = 0;        int end = n;         // Selecting each element as the start index for        // subarray        for (int i = 0; i < n; i++) {            // Initialize a set to store all distinct            // elements            HashSet<Integer> set = new HashSet<Integer>();             // Selecting the end index for subarray            int j;            for (j = i; j < n; j++) {                set.add(arr[j]);                 /*                      If set contains exactly k                    elements,then check subarray[i, j]                    is smaller in size than the current                    resultant subarray                */                               if (set.size() == k)                {                    if (j - i < end - start) {                        start = i;                        end = j;                    }                     // There are already 'k' distinct                    // elements now, no need to consider                    // further elements                    break;                }            }             // If there are no k distinct elements left              // in the array starting from index i we will break            if (j == n)                break;        }                   // If no window found then print -1        if (start == 0 && end == n)            System.out.println("Invalid k");         else            System.out.println(start + " " + end);    }     // Driver code    public static void main(String args[])    {        int arr[] = { 1, 2, 3, 4, 5 };        int n = arr.length;        int k = 3;        minRange(arr, n, k);    }} // This code is contributed by Rajdeep
# Python 3 program to find minimum range# that contains exactly k distinct numbers. # Prints the minimum range that contains# exactly k distinct numbers.def minRange(arr, n, k):     l = 0    r = n     # Consider every element as    # starting point.    for i in range(n):         # Find the smallest window starting        # with arr[i] and containing exactly        # k distinct elements.        s = []        for j in range(i, n) :            s.append(arr[j])            if (len(s) == k):                if ((j - i) < (r - l)) :                    r = j                    l = i                                 break         # There are less than k distinct        # elements now, so no need to continue.        if (j == n):            break     # If there was no window with k distinct    # elements (k is greater than total    # distinct elements)    if (l == 0 and r == n):        print("Invalid k")    else:        print(l, r) # Driver codeif __name__ == "__main__":         arr = [ 1, 2, 3, 4, 5 ]    n = len(arr)    k = 3    minRange(arr, n, k) # This code is contributed# by ChitraNayal
// C#  program to find minimum // range that contains exactly // k distinct numbers.using System;using System.Collections.Generic; public class GFG{ // Prints the minimum range // that contains exactly k // distinct numbers.public static void minRange(int[] arr, int n, int k){    int l = 0, r = n;     // Consider every element     // as starting point.    for (int i = 0; i < n; i++)    {         // Find the smallest window         // starting with arr[i] and         // containing exactly k         // distinct elements.        ISet<int> s = new HashSet<int>();        int j;        for (j = i; j < n; j++)        {            s.Add(arr[j]);            if (s.Count == k)            {                if ((j - i) < (r - l))                {                    r = j;                    l = i;                }                break;            }        }         // There are less than k         // distinct elements now,         // so no need to continue.        if (j == n)        {            break;        }    }     // If there was no window     // with k distinct elements     // (k is greater than total     // distinct elements)    if (l == 0 && r == n)    {        Console.WriteLine("Invalid k");    }    else    {        Console.WriteLine(l + " " + r);    }} // Driver code public static void Main(string[] args){    int[] arr = new int[] {1, 2, 3, 4, 5};    int n = arr.Length;    int k = 3;    minRange(arr, n, k);}} // This code is contributed by Shrikant13
<script>// Javascript program to find minimum// range that contains exactly// k distinct numbers.         // Prints the minimum range    // that contains exactly k    // distinct numbers.    function minRange(arr,n,k)    {        let l = 0, r = n;      // Consider every element    // as starting point.    for (let i = 0; i < n; i++)    {          // Find the smallest window        // starting with arr[i] and        // containing exactly k        // distinct elements.        let s = new Set();        let j;        for (j = i; j < n; j++)        {            s.add(arr[j]);            if (s.size == k)            {                if ((j - i) < (r - l))                {                    r = j;                    l = i;                }                break;            }        }          // There are less than k        // distinct elements now,        // so no need to continue.        if (j == n)            break;    }      // If there was no window    // with k distinct elements    // (k is greater than total    // distinct elements)    if (l == 0 && r == n)        document.write("Invalid k");    else        document.write(l + " " + r);    }         // Driver code    let arr=[1, 2, 3, 4, 5];    let n = arr.length;    let k = 3;    minRange(arr, n, k);              // This code is contributed by avanitrachhadiya2155</script>
0 2
Time Complexity : O(N^2) ,where N is the number of elements in the arrayEvery time picking the end points of the subarray using two nested loops(one inside another) makes the time complexity O(N^2).
Space Complexity :  O(N)In the worst case, we can have all ‘N’ elements in our set.
Approach 2 : (Sliding Window Approach)
Optimization is get rid of the repeated work while making all subarray, all subarray will not help to find the resultant. The approach is –
Steps :
Initialize a map to store the frequencies of each element. 
Taking two variables as taken before : start and end of the required subarray. 
And here we are using i and j as the starting and ending index of the window respectively, initializing as i = 0 and j = 0. 
Will traverse the array while the ending pointer of our window reach the end of given array. i.e.  while( j < n)     1.  Add the current element to the map map[ arr[j] ]++ and make j pointing to the next index     2.  Consider the window [ i, j-1 ] (reason for ‘j-1’ is as we incremented the value of ‘j’ just after insertion in last step) check whether its size is equal to k     3.  If window size is lesser then k then continue     4.  But if window size == k, then check its length whether it is the resultant subarray or not.      5.  After that we need to move our window, but in order to move our window, we have to check the starting element of our current window (i.e. i-th). If the i-th element is having a frequency of 1 then erase it from the map and else decrease its frequency by 1. And increase the i-value. Make i to point to the next element.( For understanding the reason of erase and decreasing frequency, take an example :  4 2 2 3 4 4 3 and k = 3  when we are dealing with the window 2 2 3 4 then ‘i’ would have pointed to the start of window (first 2) and ‘j’ would have pointed to the last of window (at 4). Now while moving forward (by one position), if the window totally erase 2 from the map, (and make window 2 3 4 4) then map would contain the information that 2 is not in the map but it is wrong so we will decrease the count of 2. Similarly, in case of having frequency == 1, and about to leave the window, the map should not contain the frequency of the element which not there in the window. ) 
C++
Java
Python3
C#
Javascript
// C++ program to find minimum range that// contains exactly k distinct numbers.#include <bits/stdc++.h>using namespace std; // prints the minimum range that contains exactly// k distinct numbers.void minRange(int arr[], int n, int k){    /*        start = starting index of resultant subarray        end  = ending index of resultant subarray    */    int start = 0, end = n;     unordered_map<int, int> map;     /*        i = starting index of the window (on left side)        j = ending index of the window (on right side)    */    int i = 0, j = 0;     while (j < n) {        // Add the current element to the map        map[arr[j]]++;        j++;         // Nothing to do when having less element        if (map.size() < k)            continue;         /*                If map contains exactly k elements,                consider subarray[i, j - 1] keep removing                left most elements        */         while (map.size() == k) {            // as considering the (j-1)th and i-th index            int windowLen = (j - 1) - i + 1;            int subArrayLen = end - start + 1;             if (subArrayLen > windowLen) {                start = i;                end = j - 1;            }             // Remove elements from left             // If freq == 1 then totally erase            if (map[arr[i]] == 1)                map.erase(arr[i]);             // decrease freq by 1            else                map[arr[i]]--;             // move the starting index of window            i++;        }    }     if (start == 0 && end == n)        cout << "Invalid k" << endl;     else        cout << start << " " << end << endl;} // Driver code for above function.int main(){    int arr[] = { 1, 1, 2, 2, 3, 3, 4, 5 };    int n = sizeof(arr) / sizeof(arr[0]);    int k = 3;    minRange(arr, n, k);    return 0;} // This code is contributed by Rajdeep
// Java program to find minimum range that// contains exactly k distinct numbers.import java.util.*; class GFG {     // Prints the minimum range that contains exactly    // k distinct numbers.    static void minRange(int arr[], int n, int k)    {         /*            start = starting index of resultant subarray            end  = ending index of resultant subarray        */        int start = 0, end = n;         HashMap<Integer, Integer> map = new HashMap<>();         /*            i = starting index of the window (on left side)            j = ending index of the window (on right side)        */        int i = 0, j = 0;               while (j < n) {                       // Add the current element to the map            map.put(arr[j], map.getOrDefault(arr[j], 0) + 1);            j++;                         // Nothing to do when having less element            if (map.size() < k)                continue;             /*                If map contains exactly k elements,                consider subarray[i, j - 1] keep removing                left most elements                */            while (map.size() == k)            {                  // as considering the (j-1)th and i-th index                int windowLen = (j - 1) - i + 1;                int subArrayLen = end - start + 1;                               if (windowLen < subArrayLen) {                    start = i;                    end = j - 1;                }                 // Remove elements from left                                 // If freq == 1 then totally erase                if (map.get(arr[i]) == 1)                    map.remove(arr[i]);                                   // decrease freq by 1                else                    map.put(arr[i], map.get(arr[i]) - 1);                                   // move the starting index of window                i++;            }        }         if (start == 0 && end == n)            System.out.println("Invalid k");               else            System.out.println(start + " " + end);    }     // Driver code    public static void main(String[] args)    {        int arr[] = { 1, 1, 2, 2, 3, 3, 4, 5 };        int n = arr.length;        int k = 3;         minRange(arr, n, k);    }} // This code is contributed by Rajdeep
# Python3 program to find the minimum range# that contains exactly k distinct numbers.from collections import defaultdict # Prints the minimum range that contains# exactly k distinct numbers.def minRange(arr, n, k):      # Initially left and right side is -1    # and -1, number of distinct elements    # are zero and range is n.    l, r = 0, n    i = 0    j = -1 # Initialize right side         hm = defaultdict(lambda:0)    while i < n:              while j < n:                      # increment right side.            j += 1               # if number of distinct elements less than k.            if len(hm) < k and j < n:                hm[arr[j]] += 1               # if distinct elements are equal to k            # and length is less than previous length.            if len(hm) == k and ((r - l) >= (j - i)):                              l, r = i, j                break           # if number of distinct elements less        # than k, then break.        if len(hm) < k:            break           # if distinct elements equals to k then        # try to increment left side.        while len(hm) == k:               if hm[arr[i]] == 1:                del(hm[arr[i]])            else:                hm[arr[i]] -= 1               # increment left side.            i += 1               # it is same as explained in above loop.            if len(hm) == k and (r - l) >= (j - i):                              l, r = i, j                  if hm[arr[i]] == 1:            del(hm[arr[i]])        else:            hm[arr[i]] -= 1                     i += 1       if l == 0 and r == n:        print("Invalid k")    else:        print(l, r)  # Driver code for above function.if __name__ == "__main__":      arr = [1, 1, 2, 2, 3, 3, 4, 5]     n = len(arr)    k = 3    minRange(arr, n, k)     # This code is contributed by Rituraj Jain
// C# program to find minimum// range that contains exactly// k distinct numbers.using System;using System.Collections.Generic;class GFG{     // Prints the minimum// range that contains exactly// k distinct numbers.static void minRange(int []arr,                     int n, int k){  // Initially left and  // right side is -1 and -1,  // number of distinct  // elements are zero and  // range is n.  int l = 0, r = n;   // Initialize right side  int j = -1;   Dictionary<int,             int> hm = new Dictionary<int,                                      int>();   for(int i = 0; i < n; i++)  {    while (j < n)    {      // Increment right side.      j++;       // If number of distinct elements less      // than k.      if (j < n && hm.Count < k)        if(hm.ContainsKey(arr[j]))          hm[arr[j]] = hm[arr[j]] + 1;      else        hm.Add(arr[j], 1);       // If distinct elements are equal to k      // and length is less than previous length.      if (hm.Count == k &&         ((r - l) >= (j - i)))      {        l = i;        r = j;        break;      }    }     // If number of distinct elements less    // than k, then break.    if (hm.Count < k)      break;     // If distinct elements equals to k then    // try to increment left side.    while (hm.Count == k)    {      if (hm.ContainsKey(arr[i]) &&           hm[arr[i]] == 1)        hm.Remove(arr[i]);      else      {        if(hm.ContainsKey(arr[i]))          hm[arr[i]] = hm[arr[i]] - 1;      }       // Increment left side.      i++;       // It is same as explained in above loop.      if (hm.Count == k &&         (r - l) >= (j - i))      {        l = i;        r = j;      }    }    if (hm.ContainsKey(arr[i]) &&         hm[arr[i]] == 1)      hm.Remove(arr[i]);    else      if(hm.ContainsKey(arr[i]))        hm[arr[i]] = hm[arr[i]] - 1;  }   if (l == 0 && r == n)    Console.WriteLine("Invalid k");  else    Console.WriteLine(l + " " + r);} // Driver codepublic static void Main(String[] args){  int []arr = {1, 1, 2, 2,               3, 3, 4, 5};  int n = arr.Length;  int k = 3;  minRange(arr, n, k);}} // This code is contributed by shikhasingrajput
<script>// Javascript program to find minimum// range that contains exactly// k distinct numbers              // Prints the minimum// range that contains exactly// k distinct numbers.    function minRange(arr,n,k)    {        // Initially left and right side is -1 and -1,    // number of distinct elements are zero and    // range is n.    let l = 0, r = n;          // Initialize right side    let j = -1;          let hm = new Map();          for(let i = 0; i < n; i++)    {        while (j < n)        {                          // Increment right side.            j++;              // If number of distinct elements less            // than k.            if (j < n && hm.size < k)            {                if(hm.has(arr[j]))                    hm.set(arr[j],                       hm.get(arr[j]) + 1);                else                    hm.set(arr[j],1);                          }            // If distinct elements are equal to k            // and length is less than previous length.            if (hm.size == k &&                 ((r - l) >= (j - i)))            {                l = i;                r = j;                break;            }        }          // If number of distinct elements less        // than k, then break.        if (hm.size < k)            break;          // If distinct elements equals to k then        // try to increment left side.        while (hm.size == k)        {            if (hm.has(arr[i]) && hm.get(arr[i]) == 1)                hm.delete(arr[i]);            else                if(hm.has(arr[i]))                    hm.set(arr[i],hm.get(arr[i]) - 1);              // Increment left side.            i++;              // It is same as explained in above loop.            if (hm.size == k &&                  (r - l) >= (j - i))            {                l = i;                r = j;            }        }        if (hm.has(arr[i]) && hm.get(arr[i]) == 1)            hm.delete(arr[i]);        else            if(hm.has(arr[i]))                hm.set(arr[i],hm.get(arr[i]) - 1);    }      if (l == 0 && r == n)        document.write("Invalid k");    else        document.write(l + " " + r);    }              // Driver code    let arr=[1, 1, 2, 2, 3, 3, 4, 5];    let n = arr.length;    let k = 3;    minRange(arr, n, k);         // This code is contributed by rag2127</script>
5 7
Time Complexity : O(N) ,where N is the number of elements in the arrayIn the worst case, each element will be added once and removed once from the map.
Space Complexity :  O(K)In the worst case, we can have only ‘K’ elements in our map.
This article is contributed by Rajdeep Mallick. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above. 
Kirti_Mangal
shrikanth13
ukasp
rituraj_jain
jrishabh99
shikhasingrajput
avanitrachhadiya2155
rag2127
rajdeepmallick999
sagartomar9927
cpp-unordered_map
sliding-window
Arrays
Hash
sliding-window
Arrays
Hash
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.