On m'a posé cette question d'entrevue:
Étant donné un fichier d'entrée avec quatre milliards d'entiers, fournissez un algorithme pour générer un entier qui n'est pas contenu dans le fichier. Supposons que vous disposiez de 1 Go de mémoire. Suivez ce que vous feriez si vous ne disposez que de 10 Mo de mémoire.
Mon analyse:
La taille du fichier est de 4 × 10 9 × 4 octets = 16 Go.
Nous pouvons effectuer un tri externe, nous permettant ainsi de connaître la plage des entiers.
Ma question est quelle est la meilleure façon de détecter l'entier manquant dans les grands ensembles entiers triés?
Ma compréhension (après avoir lu toutes les réponses):
En supposant que nous parlons d'entiers 32 bits, il y a 2 32 = 4 * 10 9 entiers distincts.
Cas 1: nous avons 1 Go = 1 * 10 9 * 8 bits = 8 milliards de bits de mémoire.
Solution:
Si nous utilisons un bit représentant un entier distinct, cela suffit. nous n'avons pas besoin de trier.
La mise en oeuvre:
int radix = 8;
byte[] bitfield = new byte[0xffffffff/radix];
void F() throws FileNotFoundException{
Scanner in = new Scanner(new FileReader("a.txt"));
while(in.hasNextInt()){
int n = in.nextInt();
bitfield[n/radix] |= (1 << (n%radix));
}
for(int i = 0; i< bitfield.lenght; i++){
for(int j =0; j<radix; j++){
if( (bitfield[i] & (1<<j)) == 0) System.out.print(i*radix+j);
}
}
}
Cas 2: 10 Mo de mémoire = 10 * 10 6 * 8 bits = 80 millions de bits
Solution:
Pour tous les préfixes 16 bits possibles, il y a 2 16 nombres entiers = 65536, nous avons besoin de 2 16 * 4 * 8 = 2 millions de bits. Nous avons besoin de construire 65536 godets. Pour chaque compartiment, nous avons besoin de 4 octets contenant toutes les possibilités, car le pire des cas est que les 4 milliards d'entiers appartiennent au même compartiment.
- Créez le compteur de chaque compartiment lors du premier passage dans le fichier.
- Scannez les seaux, trouvez le premier qui a touché moins de 65536.
- Créez de nouveaux compartiments dont les préfixes 16 bits élevés se trouvent dans les étapes 2 à 2 du deuxième passage du fichier
- Scannez les compartiments construits à l'étape 3, trouvez le premier compartiment qui n'a pas de succès.
Le code est très similaire à celui ci-dessus.
Conclusion: nous diminuons la mémoire en augmentant le nombre de passes de fichiers.
Une clarification pour ceux qui arrivent en retard: La question, telle que posée, ne dit pas qu'il y a exactement un entier qui n'est pas contenu dans le fichier - du moins ce n'est pas ainsi que la plupart des gens l'interprètent. De nombreux commentaires dans le fil de commentaires sont sur cette variation de la tâche, cependant. Malheureusement, le commentaire qui l'a introduit dans le fil de commentaires a été supprimé par la suite par son auteur, alors maintenant il semble que les réponses orphelines y aient tout simplement mal compris. C'est très déroutant, désolé.