Ti viene dato un file che contiene tutti i possibili numeri su un'architettura a 32 bit. Mancano 4 numeri da quel file. Trova i 4 numeri mancanti


22

Questa è una domanda di intervista che ho incontrato alcune volte e non sono davvero sicuro di come risolverlo dato che mancano quattro numeri. Ho familiarità con gli algoritmi per la ricerca di uno o due numeri mancanti, ma non vedo un modo per generalizzare nessuno dei due a quattro.


Risposte:


19

Che si tratti di un'intervista o di un vero lavoro, la tua prima priorità deve essere una soluzione di lavoro che abbia senso per te . Questo di solito significa che si dovrebbe offrire la prima soluzione si può pensare che sia semplice e facile per voi a spiegare.

Per me, questo significa ordinare i numeri e cercare spazi vuoti. Ma lavoro su sistemi aziendali e app Web. Non giocherò con i pezzi e non voglio che la mia squadra lo faccia!

Se stai intervistando per un lavoro di basso livello, più vicino al metal, probabilmente lo "smistamento" incontrerà sguardi vuoti. Vogliono che tu sia a tuo agio con i pensieri sui pezzetti e così via. La tua prima risposta dovrebbe essere "Oh, userei una bitmap". (O bit array o bit set.)

E poi, in entrambi i casi - anche se dai una soluzione "sbagliata", se il tuo intervistatore (o capo!) Preme per questo , puoi suggerire alcuni miglioramenti o alternative, concentrandoti sull'area specifica di preoccupazione del manager.

  • RAM fortemente limitata? Meno di 512 MB?
    Ordinalo sul posto, su disco. È possibile utilizzare una quantità quasi arbitraria di RAM per ottimizzare e / o bufferizzare i blocchi ordinati.
  • Tempo limitato?
    Usa quella RAM! L'ordinamento è già O(n*log(n)). (O O (n) per un ordinamento intero-bucket!)
  • Manutenibilità?
    Cosa potrebbe esserci di più semplice dell'ordinamento ?!
  • Non dimostra la conoscenza dei bit flag / campi? ( BitSet/ BitMap/ BitArray)
    Bene OK ... vai avanti e usa a BitArrayper contrassegnare i "numeri trovati". E poi cerca 0's.
  • Prevedibile complessità "in tempo reale"?
    Usa la soluzione bitmap. È un singolo passaggio sul file e un altro passaggio suBitArray/BitSet(per trovare quelli0). Questo èO(n), penso!

O qualunque cosa.

Rispondi alle preoccupazioni che hai effettivamente. Risolvi il problema prima, usando soluzioni ingenue se necessario. Non perdere il tempo di tutti affrontando preoccupazioni che non esistono ancora.


Non sono così sicuro della fattibilità di ordinare 4 miliardi di numeri con un approccio ingenuo, figuriamoci su disco. Non l'ho mai provato, però.
Eiko,

1
@Eiko Bene ... e ancora, il punto principale è ... non complicare eccessivamente le cose. Il primo passo è risolvere il problema, in qualunque modo tu possa pensare di risolverlo, anche se è ingenuo. Non posso nemmeno sottolineare il livello di frustrazione che il tuo futuro datore di lavoro avrà se passi del tempo a provare per assicurarti di avere la soluzione "giusta" quando l'azienda ha solo bisogno di una soluzione. Dimostra che puoi fare entrambe le cose! Dimostra di essere in grado di risolvere rapidamente i problemi, quindi identifica i potenziali problemi che meritano il refactoring e / o l'ottimizzazione per quanto necessario .
svidgen,

1
@Ewan "Perché hai avuto la domanda sollevata durante l'intervista" non è la stessa di "C'è una risposta specifica che ogni manager sta cercando." ... Certamente non mi importerebbe quale soluzione mi hai dato, purché tu abbia dimostrato di essere in grado di risolvere il problema e di non essere coinvolto nella risoluzione di problemi che non ti ho mai dato!
svidgen,

1
Ti manca il punto. Questa domanda e le sue variazioni si verificano in libri di puzzle di programmazione e domande di intervista. Non è stato inventato dalla persona che ha posto la domanda. si suppone che le cose a 32 bit rendano impossibile farlo tenendo traccia dei numeri o dell'ordinamento. I suoi soli computer sono diventati più veloci / più grandi da quando è stato scritto.
Ewan,

1
@Ewan: stai ancora supponendo che la tua istanza della domanda abbia gli stessi vincoli dei PO. L'OP non ha detto che il suo algoritmo deve essere eseguito su una macchina a 32 bit, non ha nemmeno detto che deve funzionare su un computer, un algoritmo concettuale potrebbe essere adatto. Inoltre, non afferma cosa significhi "tutti i numeri possibili", poiché è possibile la matematica di interi di dimensioni arbitrarie anche su microcontrollori a 8 bit. Molte ipotesi che stai facendo per dare dichiarazioni assolute.
whatsisname

19

Dal momento che è un file, suppongo che ti sia permesso fare più passaggi. Per prima cosa creare un array di 256 contatori, scorrere il file e per ogni numero incrementare il contatore indicizzato come primo byte del numero. Al termine, la maggior parte dei contatori dovrebbe essere 2 ^ 24, ma da 1 a 4 contatori dovrebbero avere valori più bassi. Ognuno di questi indici rappresenta un primo byte di uno dei numeri mancanti (se ce ne sono meno di 4 è perché più numeri mancanti condividono lo stesso primo byte).

Per ciascuno di questi indici, crea un altro array di 256 contatori e fai un secondo passaggio sul file. Questa volta, se il primo byte è uno dei valori precedenti, incrementare un contatore nella sua matrice in base al secondo byte. Al termine, cerca di nuovo i contatori inferiori a 2 ^ 16 e avrai il secondo byte dei numeri mancanti, ciascuno abbinato al suo primo byte.

Ripetere l'operazione per il terzo byte (notare che è necessario un massimo di 4 matrici in ogni passaggio, anche se ogni byte può essere seguito da un massimo di 4 byte diversi) e per il quarto byte e sono stati trovati tutti i numeri mancanti.

Complessità temporale - Complessità O(n * log n)
spaziale - costante !

Modificare:

In realtà, ho considerato il n=2^32parametro come parametro, ma anche il numero di numeri mancanti k=4è un parametro. Supponendo che k<<nciò significhi che la complessità dello spazio è O(k).

Aggiornare:

Solo per divertimento (e perché attualmente sto cercando di imparare Rust) l'ho implementato in Rust: https://gist.github.com/idanarye/90a925ebb2ea57de18f03f570f70ea1f . Ho scelto di avere una rappresentazione testuale, poiché on-one la eseguirà con ~ 2 ^ 32 numeri ...


Tenere tutti i numeri in memoria (per passaggi multipli) richiede 4 byte * 2 ^ 32 di memoria, che sta spingendo le cose. Quindi più probabilmente eseguirai tutti gli I / O quattro volte. Ma l'altra memoria utilizzata è estremamente piccola, quindi un ottimo lavoro lì.
user949300,

1
@ user949300 Suppongo che questa soluzione legga il file pezzo per pezzo piuttosto che caricare tutto in memoria contemporaneamente
Richard Tingle,

"la maggior parte dei contatori dovrebbe essere a 2 ^ 24, ma da 1 a 4 contatori dovrebbero avere valori più bassi" - sbagliato: può essere 0, con tutti i valori mancanti che condividono il primo byte (anche il secondo e il terzo sono possibili). Successivo: quanti array crei nel secondo passaggio? 256, da 1 a 4 volte 256, 256 volte 256? E poi nel terzo e quarto passaggio?
Bernhard Hiller,

3
@BernhardHiller Il file contiene tutti i possibili numeri nello spazio a 32 bit, salvo 4 numeri distinti. Pertanto, si verificheranno tutti i primi byte, solo da 1 a 4 avranno un numero inferiore di hit.
Lasse V. Karlsen,

@ LasseV.Karlsen grazie, ora capisco l'algoritmo.
Bernhard Hiller,

6

Se fosse Java, potresti usare un BitSet. Bene, due di loro, perché non riescono a contenere tutti i numeri a 32 bit. Codice scheletrico, forse buggy:

BitSet bitsetForPositives = new Bitset(2^31);  // obviously not 2^31 but you get the idea
BitSet bitsetForNegatives = new Bitset(2^31);

for (int value: valuesTheyPassInSomehow) {
  if ((value & 0x80000000) == 0)
     bitsetForPositives.set(value );
  else
     bitsetForNegatives.set(value & ~0x80000000);
}

Quindi utilizzare BitSet.nextClearBit()per trovare chi manca.

Nota aggiunta molto più tardi:

Si noti che con questo algoritmo, è abbastanza semplice eseguire la parte che richiede tempo in parallelo . Supponiamo che il file originale sia stato diviso in quattro parti approssimativamente uguali. Alloca 4 coppie di BitSet (2 GB, ancora gestibili).

  1. Hanno quattro thread, in parallelo, ciascuno dei quali elabora un file nella propria coppia di BitSet.
  2. Al termine, torna a un singolo thread o ai bit (tempo banale), quindi chiama nextClearBit quattro volte (anche tempo abbastanza banale).

Mi aspetto che l'I / O sia ancora il passo di limitazione della velocità, ma se magicamente tutti i numeri fossero in memoria si potrebbe davvero accelerare le cose.


3
@Idan Ayre. Questa soluzione richiede poco codice, quindi meno possibilità di errori di codifica. Sono carino questo è il tempo O (n). Né assume / richiede passaggi multipli attraverso un file enorme, quindi utilizza meno spazio di un algoritmo che richiede passaggi multipli. Per favore, elabora cosa intendi con "Oh caro".
user949300,

2
Non gestisce Integer.MIN_VALUEcorrettamente. È possibile mascherare il bit del segno invece di negarlo per risolverlo.
CodesInChaos,

1
Questo approccio ingenuo richiede 2 ^ 32 bit = 4 Gib = 512 MiB per i bitset, che è una modesta quantità di RAM, anche su un sistema a 32 bit.
CodesInChaos,

Se la lingua scelta non ha bitset incorporati, emulandoli utilizzando un array di byte. Ad esempio in C #:bool GetBit(byte[] byteArray, uint index) { var byteIndex = index >> 3; var bitInByte = index & 7; return (byteArray[byteIndex] >> bitInByte) & 1 != 0; }
CodesInChaos,

1
@JoulinRouge (e JacquesB) Quindi, siamo d'accordo che questo è lineare nel tempo, usa una RAM modesta (1/2 Gig) e richiede solo un passaggio di I / O. Per me va bene.
user949300,

5

Questa domanda può essere risolta usando una matrice di bit (vero / falso). Questa dovrebbe essere la struttura più efficiente per contenere le risposte per tutti i numeri usando l'indice dell'array per contenere se quel particolare numero è stato trovato.

C #

var bArray = new BitArray(Int32.MaxValue);

//Assume the file has 1 number per line
using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
            var n = int32.Parse(s);
            bArray[n] = true;
        }
}

Quindi basta scorrere attraverso l'array e per quei valori che sono ancora falsi non si trovano nel file.

È possibile suddividere il file in blocchi più piccoli, ma sono stato in grado di allocare un array di dimensioni massime int32 (2147483647) sul mio laptop da 16,0 GB con Windows 7 (64 bit).

Anche se non stavo eseguendo 64 bit, potrei allocare array di bit più piccoli. Vorrei preelaborare il file creando un set di file più piccoli ciascuno con un intervallo di [0-64000] [64001-128000], ecc. Numeri che sarebbero adatti per le risorse ambientali disponibili. Passare attraverso il file di grandi dimensioni e scrivere ogni numero nel relativo file set corrispondente. Quindi elaborare ogni file più piccolo. Ci vorrebbe un po 'più tempo a causa della fase di pre-elaborazione, ma ciò aggirerebbe le limitazioni delle risorse se ci fossero risorse limitate.


Questo non sembra gestire numeri negativi. (O ints senza segno con il bit più alto impostato se quello è l'input.) La memoria per il bitset non dovrebbe essere un problema anche sulla maggior parte dei sistemi a 32 bit.
user949300,

@ user949300 - Corretto. Non ho notato alcun grande consumo di memoria quando l'array è stato inizializzato con tutti i valori falsi. Uno avrebbe bisogno di un BitArray secondario per i numeri negativi. Forse bArrayNegative = new BitArrary (Int32.MaxValue). Quando il numero veniva letto, poteva essere verificato per positivo o negativo e quindi inserito nell'array di bit appropriato. Grazie per i commenti
Jon Raynor,

2

Dato che questa è una domanda di intervista, mostrerei all'intervistatore una certa comprensione dei vincoli. Quindi, cosa significa "tutti i numeri possibili"? È davvero 0 ... 2 <(32-1) come tutti indovinano? Le solite architetture a 32 bit possono funzionare con molti più di soli numeri a 32 bit. È solo una questione di rappresentazione, ovviamente.

Deve essere risolto su un sistema a 32 bit o è piuttosto una parte della restrizione sui numeri? Ad esempio, un tipico sistema a 32 bit non sarà in grado di caricare il file nella RAM contemporaneamente. Vorrei anche ricordare che un sistema a 32 bit spesso non sarà in grado di avere un file contenente tutti i numeri a causa della limitazione della dimensione del file. Bene, a meno che non abbia una codifica intelligente, come "Tutti i numeri tranne quei quattro", nel qual caso il problema viene risolto in modo banale.

Ma se vuoi davvero capire la domanda come "Dato un file con tutti i numeri da 0 ... 2 ^ (32-1) tranne alcuni, dammi quelli mancanti" (e questo è un grande if !), Quindi ci sono molti modi per risolverlo.

Triviale ma non fattibile: per ogni possibile numero, scansiona il file e vedi se è lì.

Con 512 MB di RAM e file a passaggio singolo: segna ogni numero (= imposta bit in quell'indice) letto dal file, quindi passa una volta la RAM e vedi quelli mancanti.


1
Alcune buone domande, ma se il sistema a 32 bit rappresenta ints, float o huzziwigs, può ancora rappresentare solo 2 ^ 32 valori in 32 bit. Se la domanda è "oh sì, consentiamo ultra-long 128 bit", allora il "vincolo" di architettura a 32 bit nella domanda è deliberatamente fuorviante. Comunque, un'ottima domanda da porre all'intervistatore, perché molte specifiche sono fuorvianti o scritte male. La tua soluzione reale è un BitSet come il mio.
user949300,

@ user949300 Sì - ed è impossibile sapere cosa sta cercando l'intervistatore. Se l'ultima persona che hanno assunto era un "accaparratore dello stack prima di pensare", la tua risposta dovrebbe essere diversa da quella di un "non ha assolutamente idea dell'architettura" o del "gioco del gioco di ottimizzazione". :) Ho già lavorato con grossi bitet (anche se non in Java), quindi mi vengono in mente naturalmente. E può essere adottato anche per memoria inferiore, se necessario (bucket). I bitset risolvono anche il "problema di ordinamento" nei commenti sopra in tempo lineare con 512 MB di RAM.
Eiko,

0

Un approccio che è facile da ricordare e facile da articolare in un'intervista sarebbe quello di utilizzare il fatto che se si guardano tutti i numeri in N bit, ciascun bit verrà impostato esattamente nella metà di quei valori e non nell'altra metà .

Se esegui l'iterazione su tutti i valori nel file e mantieni 32 conteggi dei valori alla fine, otterrai 32 valori che sono esattamente (2 ^ 32/2) o leggermente inferiori a quel valore. La differenza tra il massimo (2 ^ 32/2) e il totale fornisce i bit totali impostati in ciascuna posizione dei valori mancanti.

Una volta ottenuto ciò, è possibile determinare tutti i possibili set di 4 valori che potrebbero fornire tali totali. Detto questo, è quindi possibile scorrere nuovamente i valori nel file controllando eventuali valori che fanno parte di tali combinazioni. Quando ne trovi uno, le combinazioni che contengono quel valore vengono eliminate come possibilità. Una volta che è rimasta una sola combinazione possibile, hai la risposta.

Ad esempio utilizzando un bocconcino, hai i seguenti valori:

1010
0110
1111
0111
1101
1001
0100
0101
0001
1011
1100
1110

I bit totali impostati in ciascuna posizione sono:

7867

Sottraendo quelli da 8 (4 ^ 2/2) otteniamo:

1021

Ciò significa che ci sono questi seguenti possibili set di 4 valori:

1000
0000
0011
0010

1010
0001
0010
0000

(perdonami se ne ho perso qualcuno, lo sto facendo solo a vista)

E poi guardando di nuovo i numeri originali, troviamo subito 1010, il che significa che il primo set è stata la risposta.


ma devi trovare 4 numeri, non uno
freedev,

@freedev Hai ragione. Questo è quello che fa. Un set di quattro numeri è quattro numeri ... in un set.
JimmyJames,

Interessante, ma ti sorprendi determine all the possible sets of 4 values that could give those totals. Penso davvero che questa sia una parte importante della soluzione che manca alla tua risposta. Può anche influire sulla complessità del tempo e dello spazio.
Allon Guralnek,

@AllonGuralnek Hai ragione. Ho passato un po 'di tempo a lavorare su questo e avevo ampiamente sottovalutato quanti set di 4 numeri si sarebbero aggiunti allo stesso numero nel peggiore dei casi. Penso che sia un'idea salvabile, ma è un po 'più complicata di quanto non abbia esposto qui. Aggiornerò più avanti con i dettagli. Apprezzo il feedback.
JimmyJames,

0

Supponendo che il file sia ordinato per numero crescente:

Assicurati che contenga effettivamente (2³²-4) numeri.
Ora se il file fosse completo (o se i 4 numeri mancanti fossero gli ultimi 4), la lettura di qualsiasi parola nel file nella posizione N restituirebbe il valore corrispondente N.

Utilizzare una ricerca dicotomica sulle posizioni [0..2³²-4-1) per cercare il primo numero X1 non previsto.
Una volta trovato quel primo numero mancante, eseguire nuovamente una ricerca della dictotomia sulle posizioni [X1 .. (2³²-4-1)] per trovare il secondo mancante, X2: Questa volta, leggendo una parola nella posizione N dovrebbe restituire il valore corrispondente N-1 se non c'erano più numeri mancanti (poiché hai superato un numero mancante).
Iterate allo stesso modo per i due numeri rimanenti. Nella terza iterazione, la lettura della parola nella posizione N dovrebbe restituire N-2, e nella quarta, dovrebbe restituire N-3.

Avvertenza: non l'ho testato. Ma penso che dovrebbe funzionare. :)

Ora nella vita reale, sono d'accordo con altre risposte: le prime domande riguarderebbero l'ambiente. Abbiamo RAM a disposizione (quanto), è il file su un dispositivo di archiviazione ad accesso diretto, si tratta di un'operazione one-shot (nessuna ottimizzazione richiesta) o critica (abbiamo un conteggio di ogni ciclo), abbiamo un'utilità di ordinamento esterna disponibile , ecc.
Quindi trovare un compromesso accettabile per il contesto. Questo almeno mostra che inizi ad analizzare il problema prima di cercare un algoritmo.


-2

Come per tutte le domande standard, la soluzione è di cercarle su Google prima dell'intervista.

Questa domanda e le variazioni hanno una risposta "corretta" ben definita che coinvolge XORing tutti i numeri. Dovrebbe mostrarti capire gli indici nei database o qualcosa del genere. Quindi zero punti per ogni "potrebbe funzionare, ma non quello che dice sulla carta" rispondo in modo rapido.

Tra i lati positivi c'è una serie finita di queste domande che alcune ore di revisione ti faranno sembrare un genio. Ricorda solo di far finta di averlo fatto in testa.

Modificare. Ahh sembra che per 4 esiste un approccio diverso rispetto a XOR

http://books.google.com/books?id=415loiMd_c0C&lpg=PP1&dq=muthukrishnan%20data%20stream%20algorithms&hl=el&pg=PA1#v=onepage&q=muthukrishnan%20data%20stream%20algorithms&f=false

Modificare. Downvoter: questa è una soluzione di testo pubblicata O (n) al problema esatto indicato nel PO.


1
In particolare, questo libro collegato è interamente dedicato all'elaborazione in streaming. In particolare, l'elaborazione del flusso all'interno di vincoli. Detto questo, certamente avrei convinto che questa è l'origine della questione del PO ha visto, dal momento che è altrimenti piuttosto banale. In particolare, non hai effettivamente risposto alla domanda. Avrai +1 da me se puoi convincerlo in modo convincente come la domanda "originale" o "prevista" e spiegare la soluzione ... ma, questo non risponde a nulla così com'è.
svidgen,

1
Questa risposta (in un'intervista) mostra solo che hai letto il libro. Niente sulle tue abilità o sui tuoi processi mentali. E come si fa a "google tutte le domande standard " prima di un'intervista? Esiste un elenco finito di "tutte le domande mai poste in un'intervista" che mi sono perso?
user949300,

1
@ewan sottolinea anche la difficoltà di assumere un buon candidato! Se i "bravi" sono semplicemente ben preparati per le domande del colloquio ... Diventa difficile assumere qualcuno che possa effettivamente risolvere i miei problemi commerciali?
svidgen,

1
@ewan Per essere chiaro, mi stavo prendendo in giro la mia punteggiatura errata. ... In ogni caso, tieni presente che ho ricevuto anche un discreto numero di offerte di lavoro ai miei giorni, anche se sono maledettamente ignaro delle domande e risposte standard come questa. E ora, come responsabile delle assunzioni, posso prometterti che non voglio risposte recitate ... Tuttavia, capisco che alcuni manager avranno esigenze diverse.
svidgen,

1
@Ewan Dovrei anche chiarire un'altra cosa, se il mio tono non è stato ricevuto come previsto: dovresti rivedere la tua risposta per affermare effettivamente che il problema nel libro collegato è la "domanda prevista". E poi rispondi alla domanda! ... È senza dubbio sarebbe la mia 1, e gli altri abbondanza, e la soddisfazione di aiutare il PO per farlo.
svidgen,
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.