Subarreglo más pequeño con k números distintos

Nos dan una array que consta de n enteros y un entero k. Necesitamos encontrar el rango mínimo en el arreglo [l, r] (tanto l como r son inclusivos) tal que haya exactamente k números diferentes. Si tal subarreglo no existe, imprima «K no válido».
Ejemplos: 

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

Enfoque 1: (Método de fuerza bruta)

El enfoque más simple en este problema es intentar generar todos los subarreglos y verificar para qué subarreglo el tamaño es k. Pero hay algunos puntos que debemos cuidar.

Pasos:

  1. Elija cada uno de los elementos de la array dada como el elemento inicial [i-ésimo elemento] de nuestra subarreglo requerido.
  2. En cada iteración, inicialice un conjunto vacío para almacenar los distintos elementos del subarreglo
    • Elija cada elemento restante [i, i+1,..n – 1] de la array como el último elemento [j-ésimo elemento].
    • Añade el elemento actual al conjunto.
    • Si el tamaño del conjunto es igual a k , actualice los resultados y rompa con el ciclo interno (ya se encontraron k elementos distintos que aumentan el tamaño del subarreglo tiene 2 posibilidades, obtendrá más elementos distintos o aumentará el tamaño del subarreglo con elementos repetidos que no son para considerarse en los resultados requeridos).
  3. Si (j == n) o j = tamaño de la array, es decir, no hemos encontrado ningún subarreglo deseado a partir del i-ésimo índice y en el futuro tendremos menos elementos para considerar.
    (Por ejemplo: considere que el conjunto dado es 4 5 5 4 5  y k = 3 , cuando comience desde el índice 0 no encontraremos ningún subarreglo de tamaño k y j llegará al final, lo que significa que no obtendremos ningún elemento que pueda hacer ak = 3 subarreglo de tamaño requerido). 
    Entonces, rompe con el bucle exterior.
  4. Imprima la salida si la encuentra; de lo contrario, imprima «K no válida» .

Implementación:

C++

// 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

// 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

# 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 code
if __name__ == "__main__":
     
    arr = [ 1, 2, 3, 4, 5 ]
    n = len(arr)
    k = 3
    minRange(arr, n, k)
 
# This code is contributed
# by ChitraNayal

C#

// 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

Javascript

<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>
Producción

0 2

Complejidad de tiempo: O (N ^ 2) , donde N es el número de elementos en la array. Cada vez que se seleccionan los puntos finales del subarreglo usando dos bucles anidados (uno dentro de otro), la complejidad del tiempo es O (N ^ 2).
Complejidad espacial: O (N), en el peor de los casos, podemos tener todos los elementos ‘N’ en nuestro conjunto.

Enfoque 2: (Enfoque de ventana deslizante)

La optimización es deshacerse del trabajo repetido al hacer todos los subarreglos, todos los subarreglos no ayudarán a encontrar el resultante. El enfoque es –

Pasos :

  • Inicialice un mapa para almacenar las frecuencias de cada elemento.
  • Tomando dos variables como se tomaron antes: inicio y final del subarreglo requerido.
  • Y aquí estamos usando i y j como el índice inicial y final de la ventana respectivamente, inicializando como i = 0 y j = 0 .
  • Recorrerá la array mientras el puntero final de nuestra ventana alcance el final de la array dada. es decir   , mientras ( j < n)
    1. Agregue el elemento actual al mapa map[ arr[j] ]++ y haga que j apunte al siguiente índice
    2. Considere la ventana [i, j-1] (el motivo de ‘j-1’ es que incrementamos el valor de ‘j’ justo después de la inserción en el último paso) verifique si su tamaño es igual a k
    3. Si el tamaño de la ventana es menor que k , continúe
    4. Pero si el tamaño de la ventana == k , entonces verifique su longitud si es el subarreglo resultante o no. 
    5. Después de eso, necesitamos mover nuestra ventana, pero para mover nuestra ventana, debemos verificar el elemento inicial de nuestra ventana actual (es decir , i-th ). Si el i-ésimo elemento tiene una frecuencia de 1, bórrelo del mapa y disminuya su frecuencia en 1. Y aumente el valor de i. Haz que i apunte al siguiente elemento.

(Para comprender el motivo del borrado y la disminución de la frecuencia, tome un ejemplo: 4 2 2 3 4 4 3 y k = 3  cuando estamos tratando con la ventana 2 2 3 4 entonces ‘i’ habría apuntado al inicio de la ventana ( primero 2 ) y ‘j’ habría apuntado a la última ventana (en 4 ). Ahora, mientras avanza (una posición), si la ventana borra totalmente 2 del mapa, (y hace que la ventana sea 2 3 4 4 ), entonces map contendría la información de que 2 no está en el mapa pero está malpor lo que disminuiremos la cuenta de 2. De igual forma, en caso de tener frecuencia == 1, ya punto de salir de la ventana, el mapa no debe contener la frecuencia del elemento que no está en la ventana. )

Implementación:

C++

// 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

// 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

# 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#

// 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 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 shikhasingrajput

Javascript

<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>
Producción

5 7

Complejidad de tiempo: O(N) , donde N es el número de elementos en la array. En el peor de los casos, cada elemento se agregará una vez y se eliminará una vez del mapa.
Complejidad espacial: O(K), en el peor de los casos, solo podemos tener elementos ‘K’ en nuestro mapa.

Este artículo es una contribución de Rajdeep Mallick . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *