Trovare l'elemento che si presenta maggiormente in un file molto grande


12

Ho ascoltato molto questa domanda di intervista e speravo di ottenere alcune opinioni su quali potrebbero essere le risposte valide: hai un file di grandi dimensioni da 10+ GB e vuoi scoprire quale elemento si presenta di più, qual è un buon modo per farlo?

Iterare e tenere traccia di una mappa non è probabilmente una buona idea poiché si utilizza molta memoria e tenere traccia quando arrivano le voci non è la migliore opzione poiché quando si pone questa domanda il file di solito esiste già.

Altri pensieri che avevo incluso dividendo il file per essere ripetuti ed elaborati da più thread e quindi combinare quei risultati, ma il problema di memoria per le mappe è ancora lì.


2
Quali sono gli elementi del file? Sono stringhe? Se prendi i caratteri per gli elementi, la mappa non avrebbe un problema di memoria. Se gli elementi sono parole, di nuovo penso che non sarebbe un problema. Se hai tutte le sottostringhe possibili, allora potresti avere problemi ...
Nejc

1
Se la condizione era "un elemento che appare più della metà degli elementi totali", c'era una soluzione lineare.
st0le

Credo che gli elementi siano di solito stringhe. Ma non vedo come la mappa non sia un problema. Nel caso peggiore in cui ogni elemento è unico, non hai appena raddoppiato il tuo requisito di memoria?
Pat

1
Se è applicabile l'algoritmo candidato alla maggioranza di Boyer-Moore, viene eseguito in un tempo lineare ed è attivo.
Juho,

Risposte:


6

>1/kO(k)O(). Il problema è ora noto come il problema dei battitori pesanti (gli elementi frequenti sono i battitori pesanti).

>1/kk

k=2

  • se l'elemento corrente del file è uguale all'elemento memorizzato, aumentare il conteggio di uno
  • se l'elemento corrente del file è diverso dall'elemento memorizzato, ridurre il conteggio di uno
  • se il conteggio aggiornato è 0, "elimina" l'elemento memorizzato e memorizza l'elemento corrente del file; aumentare il conteggio a 1
  • passare all'elemento successivo del file

Un po 'di riflessione su questa procedura ti convincerà che se esiste un elemento "maggioranza", cioè uno che si verifica più della metà delle volte, quell'elemento sarà l'elemento memorizzato dopo che l'intero file è stato elaborato.

kk1k1kk

k11/kO(k)

k1/kk1


Non è possibile utilizzare gli algoritmi di Boyer-Moore o Misra-Gries-Demaine. Il problema, come affermato, è diverso: non stai cercando un elemento di maggioranza, ma un elemento le cui occorrenze sono> = delle occorrenze di tutti gli elementi. Ecco un semplice controesempio. Sia n il numero totale di elementi, tale che n = 2k + 1 . Lascia che i primi k elementi siano 0, i successivi k elementi siano 1 e l'ultimo elemento sia 2. L'algoritmo Boyer-Moore riporterà l'ultimo elemento, 2, come potenziale candidato a maggioranza. Ma, in questo caso particolare, l'output deve essere 0 o 1.
Massimo Cafaro,

O(1)Ω(n)

Ho appena sottolineato che se si fa un'ipotesi sbagliata, si potrebbero ottenere risultati sbagliati. Cosa c'è di meglio, un ingombro di memoria ridotto e un risultato potenzialmente errato o il risultato corretto anche se ti costa un po 'più di memoria? Se dovessi scegliere un risultato potenzialmente errato, sceglierei un algoritmo randomizzato piuttosto che per Boyer-Moore supponendo che qualcosa che non conosco sia effettivamente vero.
Massimo Cafaro,

@MassimoCafaro che non è un compromesso che devi prendere. come ho sottolineato un singolo passaggio sul file verifica facilmente se il presupposto è soddisfatto!
Sasho Nikolov,

@MassimoCafaro e questa è solo la soluzione banale! l'assunzione può essere verificata con alta probabilità con uno schizzo CM senza passaggi aggiuntivi.
Sasho Nikolov,

3

La risposta ovvia è ovviamente quella di mantenere una mappa hash e archiviare un contatore del verificarsi di elementi mentre ci si sposta nel file come Nejc ha già suggerito. Questa è (in termini di complessità temporale) la soluzione ottimale.

Θ(nlogn).


Potresti approfondire l'approccio alla codifica di Huffman? Ho già scritto un codificatore Huffman ma è passato un po ', come lo useresti esattamente in questo caso?
Pat

@Pat Nevermind quella parte era troppo presto la mattina e in qualche modo ho pensato che avrebbe senso comprimere l'input.
Jernej,

1

Se l'elemento più comune è più comune del successivo elemento comune per un margine sostanziale e il numero di elementi diversi è piccolo rispetto alla dimensione del file, è possibile campionare casualmente un paio di elementi e restituire l'elemento più comune nel campione.


Inoltre, se si verificano molte volte un numero limitato di elementi, è possibile trovarli campionando e quindi contare esattamente questi elementi.
Max
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.