Encontrar el elemento que ocurre más en un archivo muy grande

12

Escuché mucho esta pregunta de la entrevista y esperaba obtener algunas opiniones sobre cuáles podrían ser buenas respuestas: tiene un archivo grande de más de 10 GB y desea saber qué elemento se produce más, cuál es una buena manera ¿para hacer esto?

Iterar y realizar un seguimiento en un mapa probablemente no sea una buena idea, ya que usa mucha memoria, y realizar un seguimiento a medida que ingresan las entradas no es la mejor opción, ya que cuando se plantea esta pregunta, el archivo generalmente ya existe.

Otros pensamientos que incluí dividir el archivo para ser iterado y procesado por múltiples subprocesos y luego combinar esos resultados, pero el problema de memoria para los mapas sigue ahí.

Palmadita
fuente
2
¿Cuáles son los elementos del archivo? ¿Son cuerdas? Si toma caracteres para elementos, entonces el mapa no tendría un problema de memoria. Si los elementos son palabras, creo que no sería un problema. Si tiene todas las subcadenas posibles, entonces puede tener problemas ...
Nejc
1
Si la condición era "un elemento que aparece más de la mitad de los elementos totales", entonces había una solución lineal.
st0le
Creo que los elementos suelen ser cadenas. Pero no veo cómo el mapa no es un problema. En el peor de los casos donde cada elemento es único, ¿no acabas de duplicar el requisito de memoria?
Pat
1
Si el algoritmo de candidato mayoritario de Boyer-Moore es aplicable, se ejecuta en tiempo lineal y está en su lugar.
Juho

Respuestas:

6

>1/kO(k)O(). El problema ahora se conoce como el problema de los bateadores pesados ​​(los elementos frecuentes son los bateadores pesados).

>1/kk

k=2

  • Si el elemento actual del archivo es el mismo que el elemento almacenado, aumente el recuento en uno
  • Si el elemento actual del archivo es diferente del elemento almacenado, disminuya el recuento en uno
  • si el recuento actualizado es 0, "expulse" el elemento almacenado y almacene el elemento actual del archivo; aumentar el recuento a 1
  • proceder al siguiente elemento del archivo

Un poco de reflexión sobre este procedimiento lo convencerá de que si existe un elemento "mayoritario", es decir, uno que se produce más de la mitad del tiempo, ese elemento será el elemento almacenado después de que se procese todo el archivo.

kk1k1kk

k11/kO(k)

k1/kk1

Sasho Nikolov
fuente
No puede usar los algoritmos Boyer-Moore o Misra-Gries-Demaine. El problema como se indicó es diferente: no está buscando un elemento mayoritario, sino un elemento cuyas ocurrencias son> = de las ocurrencias de todos los elementos. Aquí hay un contraejemplo simple. Sea n el número total de elementos, de modo que n = 2k + 1 . Deje que los primeros k elementos sean 0, los siguientes k elementos sean 1 y el último elemento sea 2. El algoritmo de Boyer-Moore informará el último elemento, 2, como el candidato potencial de la mayoría. Pero, para este caso particular, la salida debe ser 0 o 1.
Massimo Cafaro
O(1)Ω(n)
Acabo de señalar que si hace una suposición incorrecta, puede obtener resultados incorrectos. ¿Qué es mejor, una pequeña huella de memoria y un resultado potencialmente incorrecto o el resultado correcto aunque le cueste más memoria? Si tuviera que elegir un resultado potencialmente incorrecto, elegiría un algoritmo aleatorio en lugar de Boyer-Moore, suponiendo que algo que no sé es realmente cierto.
Massimo Cafaro
@MassimoCafaro que no es una compensación que debe tomar. Como señalé, una sola pasada sobre el archivo verifica fácilmente si se cumple el supuesto.
Sasho Nikolov
@MassimoCafaro y esta es solo la solución trivial! la suposición se puede verificar con alta probabilidad con un boceto CM sin pases adicionales.
Sasho Nikolov
3

La respuesta obvia es, por supuesto, mantener un mapa hash y almacenar un contador de la aparición de elementos a medida que avanza por el archivo como Nejc ya sugirió. Esta es (en términos de complejidad temporal) la solución óptima.

Θ(nlogn).

Jernej
fuente
¿Podría elaborar más sobre el enfoque de codificación de Huffman? He escrito un codificador Huffman antes, pero ha pasado un tiempo, ¿cómo exactamente lo usarías en este caso?
Pat
@Pat No importa que parte era demasiado temprano en la mañana y de alguna manera pensé que tendría sentido comprimir la entrada.
Jernej
1

Si el elemento más común es más común que el siguiente elemento común por un margen sustancial, y el número de elementos diferentes es pequeño en comparación con el tamaño del archivo, puede muestrear aleatoriamente un par de elementos y devolver el elemento más común en su muestra.

adrianN
fuente
Además, si hay un pequeño número de elementos que ocurren muchas veces, puede encontrarlos por muestreo y luego contar solo estos elementos exactamente.
Max