Me han dado esta pregunta de entrevista:
Dado un archivo de entrada con cuatro mil millones de enteros, proporcione un algoritmo para generar un entero que no esté contenido en el archivo. Suponga que tiene 1 GB de memoria. Haga un seguimiento de lo que haría si tuviera solo 10 MB de memoria.
Mi analisis:
El tamaño del archivo es 4 × 10 9 × 4 bytes = 16 GB.
Podemos hacer una ordenación externa, lo que nos permite conocer el rango de los enteros.
Mi pregunta es ¿cuál es la mejor manera de detectar el entero que falta en los conjuntos de enteros grandes ordenados?
Mi entendimiento (después de leer todas las respuestas):
Suponiendo que estamos hablando de enteros de 32 bits, hay 2 32 = 4 * 10 9 enteros distintos.
Caso 1: tenemos 1 GB = 1 * 10 9 * 8 bits = memoria de 8 mil millones de bits.
Solución:
Si usamos un bit que representa un número entero distinto, es suficiente. No necesitamos ordenar.
Implementación:
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);
}
}
}
Caso 2: 10 MB de memoria = 10 * 10 6 * 8 bits = 80 millones de bits
Solución:
Para todos los posibles prefijos de 16 bits, hay 2 16 número de enteros = 65536, necesitamos 2 16 * 4 * 8 = 2 millones de bits. Necesitamos construir 65536 cubos. Para cada segmento, necesitamos 4 bytes que contengan todas las posibilidades porque el peor de los casos es que todos los 4 mil millones de enteros pertenecen al mismo segmento.
- Construya el contador de cada cubo a través de la primera pasada a través del archivo.
- Escanee los cubos, encuentre el primero que tenga menos de 65536 golpes.
- Cree nuevos cubos cuyos altos prefijos de 16 bits se encuentran en el paso 2 al segundo paso del archivo
- Escanee los cubos construidos en el paso 3, encuentre el primer cubo que no tenga éxito.
El código es muy similar al anterior.
Conclusión: disminuimos la memoria al aumentar el paso del archivo.
Una aclaración para quienes llegan tarde: la pregunta, como se hizo, no dice que haya exactamente un número entero que no esté contenido en el archivo, al menos esa no es la forma en que la mayoría de las personas lo interpreta. Sin embargo, muchos comentarios en el hilo de comentarios son sobre esa variación de la tarea. Desafortunadamente, el comentario que lo introdujo en el hilo de comentarios fue eliminado más tarde por su autor, por lo que ahora parece que las respuestas huérfanas simplemente lo malinterpretaron todo. Es muy confuso, lo siento.
int getMissingNumber(File inputFile) { return 4; }
( referencia )