Smallest Subarray with k Distinct Numbers

Difficulty Level Hard
Frequently asked in Amazon Google
Array Hash Sliding Window Two PointerViews 2739

Suppose, you have an integer array and a number k. The problem statement asks to find out the smallest sub-array of range (l, r) inclusively, in such a way there are exactly k distinct numbers present in that smallest sub-array.

Example

Input:

{1, 2, 2, 3, 4, 5, 5}

k=3

Output:

2, 4

Explanation:

{2, 3, 4} is the smallest sub-array starting from 2nd index to 4th index with k i.e., 3 distinct elements.

Input:

{2, 5, 6, 7}

k=2

Output:

2, 3

Explanation:

{2, 5} is the smallest sub-array starting from 2nd index to 3rd index with k ie., 2 distinct elements.

Algorithm

  1. Set the distinct element to 0 and left side and right side pointers to -1.
  2. Traverse through the array,
  3. Incrementing right side by 1, if no of distinct elements is less than the given number k,
  4. Then increase the count and store the frequency of array element into the map.
  5. If distinct elements are equal to the given number k and the length so formed is smaller than the previously updated length, then left and right side pointers and break.
  6. If the number of distinct elements found to be less than k then break.
  7. Check if the number of distinct elements found to be equal to k, then increase the right side pointers.
  8. If distinct elements are equal to the given number k and the length so formed is smaller than the previously updated length, then left and right side pointers and break.
  9. Check if the frequency of the element is found to be 1, then remove that element from the map, else decrease the count of the frequency of that element
  10. If the left side pointer is found to be 0 and the right side to be equal to n, it means it is invalid.
  11. Else, print the left side and right side values.

Explanation

Store each array elements frequency while traversing the array, and pick each array element, and check if map size is less than k if it is found to be less than k than we need to count and store the frequency of that array element and if the map size founds to be k(distinct element number) and also the current length is less than the previous length of the sub-array, then we will update the left side and right side pointers. This all will go in a loop, till the whole map is traversed once.

If the size of a map founds to be less than k, then break. We have got the values on a map. Loop will go till the size of the map found to be equal to k, the frequency of array element in a map is found to be equal to 1, then we need to remove that particular element from the map, else we need to decrease the frequency of that particular element from a map. Again we are going to check if the map size is equal to k and the length of the current sub-array is less than the previously updated length, then, update the left side and right side pointers. If the frequency of the array element is 1, then remove that element else decrease the frequency of the element.

After traversal of the array, if the left side pointer is found to be 0 and the right side pointer to n, that means it is an invalid k. Else print the value of the left and right side pointer, which would be the starting point and ending point of the smallest sub-array inclusively.

Implementation

C++ program for Smallest Subarray with k Distinct Numbers#include<iostream>

#include<map>

using namespace std;

void getSmallestSubarray(int arr[], int n, int k)
{
    int left = 0, right = n;
    int j = -1;
    map<int, int> MAP;
    for (int i=0; i<n; i++)
    {
        while (j < n)
        {
            j++;
            if (MAP.size() < k)
                MAP[arr[j]]++;

            if (MAP.size() == k && ((right - left) >= (j - i)))
            {
                left = i;
                right = j;
                break;
            }

        }
        if (MAP.size() < k)
            break;

        while (MAP.size() == k)
        {
            if (MAP[arr[i]] == 1)
                MAP.erase(arr[i]);
            else
                MAP[arr[i]]--;

            i++;

            if (MAP.size() == k && (right - left) >= (j - i))
            {
                left = i;
                right = j;
            }
        }
        if (MAP[arr[i]] == 1)
            MAP.erase(arr[i]);
        else
            MAP[arr[i]]--;
    }
    if (left == 0 && right == n)
        cout << "Invalid k" << endl;
    else
        cout << left << " " << right;
}
int main()
{
    int arr[] = {1, 2, 2, 3, 4, 5, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 3;
    getSmallestSubarray(arr, n, k);
    return 0;
}
2 4

Java program for Smallest Subarray with k Distinct Numbers

import java.util.HashMap;
import java.util.Map;
class smallestSubArray
{
    public static void getSmallestSubarray(int arr[], int n, int k)
    {
        int left = 0, right = n;
        int j = -1;
        HashMap<Integer, Integer> MAP=new HashMap<>();
        for (int i=0; i<n; i++)
        {
            while (j < n-1)
            {
                j++;
                if (MAP.size() < k)
                {

                    if(MAP.containsKey( arr[j] ))
                        MAP.put( arr[j], MAP.get( arr[j] ) + 1 );
                    else
                        MAP.put(arr[j],1);
                }

                if (MAP.size() == k && ((right - left) >= (j - i)))
                {
                    left = i;
                    right = j;
                    break;
                }
            }
            if (MAP.size() < k)
                break;

            while (MAP.size() == k)
            {
                if (MAP.get(arr[i]) == 1)
                    MAP.remove(arr[i]);
                else
                    MAP.put(arr[i], MAP.get(arr[i])-1);

                i++;

                if (MAP.size() == k && (right - left) >= (j - i))
                {
                    left = i;
                    right = j;
                }
            }
            if (MAP.get(arr[i]) == 1)
                MAP.remove(arr[i]);
            else
                MAP.put(arr[i], MAP.get(arr[i])-1);
        }
        if (left == 0 && right == n)
            System.out.println("Invalid k");
        else
            System.out.println(left+" "+right);
    }
    public static void main(String [] args)
    {
        int arr[] = {1, 2, 2, 3, 4, 5, 5};
        int n = arr.length;
        int k = 3;
        getSmallestSubarray(arr, n, k);

    }
}
2 4

Complexity Analysis for Smallest Subarray with k Distinct Numbers

Time Complexity

O(n) where “n” is the number of elements in the array.

Space Complexity

O(n) where “n” is the number of elements in the array.

Translate »