Recebi esta pergunta da entrevista:
Dado um arquivo de entrada com quatro bilhões de números inteiros, forneça um algoritmo para gerar um número inteiro que não esteja contido no arquivo. Suponha que você tenha 1 GB de memória. Siga o que você faria se tivesse apenas 10 MB de memória.
Minha análise:
O tamanho do arquivo é 4 × 10 9 × 4 bytes = 16 GB.
Podemos fazer uma classificação externa, informando o intervalo dos números inteiros.
Minha pergunta é qual é a melhor maneira de detectar o número inteiro ausente nos grandes conjuntos inteiros classificados?
Meu entendimento (depois de ler todas as respostas):
Supondo que estamos falando de números inteiros de 32 bits, existem 2 32 = 4 * 10 9 inteiros distintos.
Caso 1: temos 1 GB = 1 * 10 9 * 8 bits = 8 bilhões de bits de memória.
Solução:
Se usarmos um bit representando um número inteiro distinto, é suficiente. nós não precisamos de classificação.
Implementação:
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 memória = 10 * 10 6 * 8 bits = 80 milhões de bits
Solução:
Para todos os possíveis prefixos de 16 bits, existem 2 16 números inteiros = 65536, precisamos de 2 16 * 4 * 8 = 2 milhões de bits. Precisamos construir 65536 baldes. Para cada bloco, precisamos de 4 bytes com todas as possibilidades, porque o pior caso é que todos os 4 bilhões de números inteiros pertencem ao mesmo bloco.
- Crie o contador de cada balde através da primeira passagem pelo arquivo.
- Digitalize os baldes, encontre o primeiro com menos de 65536 acertos.
- Crie novos buckets cujos altos prefixos de 16 bits são encontrados na etapa 2 até a segunda passagem do arquivo
- Examine os baldes construídos na etapa 3, encontre o primeiro balde que não tem sucesso.
O código é muito semelhante ao acima.
Conclusão: diminuímos a memória através do aumento da passagem de arquivos.
Um esclarecimento para quem chega atrasado: a pergunta, como feita, não diz que há exatamente um número inteiro que não está contido no arquivo - pelo menos não é assim que a maioria das pessoas o interpreta. Muitos comentários no segmento de comentários são sobre essa variação da tarefa, no entanto. Infelizmente, o comentário que o introduziu no tópico foi posteriormente excluído por seu autor, agora parece que as respostas órfãs a ele apenas entendiam tudo errado. É muito confuso, desculpe.
int getMissingNumber(File inputFile) { return 4; }
( referência )