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.
fonte
int getMissingNumber(File inputFile) { return 4; }
( referência )Respostas:
Supondo que "número inteiro" signifique 32 bits : 10 MB de espaço é mais que suficiente para você contar quantos números existem no arquivo de entrada com um prefixo de 16 bits, para todos os prefixos de 16 bits possíveis em uma passagem pelo Arquivo de entrada. Pelo menos um dos baldes será atingido menos de 2 16 vezes. Faça uma segunda passagem para descobrir qual dos números possíveis nesse intervalo já está sendo usado.
Se isso significa mais do que 32 bits, mas ainda de tamanho limitado : faça o seguinte, ignorando todos os números de entrada que estiverem fora do intervalo de 32 bits (assinado ou não; sua escolha).
Se "número inteiro" significa número inteiro matemático : leia a entrada uma vez e acompanhe o
maior número decomprimento do número mais longo que você já viu. Quando terminar, imprimao máximo mais umnúmero aleatório com mais um dígito. (Um dos números no arquivo pode ser um bignum que leva mais de 10 MB para representar exatamente, mas se a entrada for um arquivo, você poderá pelo menos representar o comprimento de qualquer coisa que se encaixe nele).fonte
Algoritmos estatisticamente informados resolvem esse problema usando menos passagens do que abordagens determinísticas.
Se números inteiros muito grandes forem permitidos , será possível gerar um número que provavelmente será único no tempo O (1). Um número inteiro pseudo-aleatório de 128 bits, como um GUID , só colidirá com um dos quatro bilhões de inteiros existentes no conjunto em menos de um em cada 64 bilhões de bilhões de casos.
Se os números inteiros estiverem limitados a 32 bits , é possível gerar um número que provavelmente será único em uma única passagem usando muito menos que 10 MB. As probabilidades de um número inteiro pseudo-aleatório de 32 bits colidir com um dos 4 bilhões de inteiros existentes são de cerca de 93% (4e9 / 2 ^ 32). A probabilidade de que 1000 inteiros pseudo-aleatórios colidam é menor que uma em 12.000 bilhões de bilhões de bilhões (probabilidade de uma colisão ^ 1000). Portanto, se um programa mantém uma estrutura de dados contendo 1000 candidatos pseudo-aleatórios e itera pelos números inteiros conhecidos, eliminando correspondências dos candidatos, é quase certo que você encontrará pelo menos um número inteiro que não esteja no arquivo.
fonte
Uma discussão detalhada sobre esse problema foi discutida em Jon Bentley "Coluna 1. Quebrando a ostra" Pérolas de programação Addison-Wesley pp.3-10
Bentley discute várias abordagens, incluindo ordenação externa, Merge Sort usando vários arquivos externos etc., mas o melhor método Bentley sugere é um único algoritmo de passagem usando campos de bits , que ele ironicamente chama de "Maravilha Sort" :) Vindo para o problema, 4 bilhões números podem ser representados em:
O código para implementar o conjunto de bits é simples: (retirado da página de soluções )
O algoritmo de Bentley faz uma única passagem sobre o arquivo,
set
marcando o bit apropriado na matriz e, em seguida, examina essa matriz usando atest
macro acima para encontrar o número ausente.Se a memória disponível for menor que 0,466 GB, Bentley sugere um algoritmo k-pass, que divide a entrada em intervalos, dependendo da memória disponível. Para dar um exemplo muito simples, se apenas 1 byte (ou seja, memória para processar 8 números) estivesse disponível e o intervalo fosse de 0 a 31, dividimos isso em intervalos de 0 a 7, 8-15, 16-22 e assim por diante e lide com esse intervalo em cada uma das
32/8 = 4
passagens.HTH.
fonte
!= -1
ainda sature a largura de banda da memória em execução em um único núcleo (este é o SIMD dentro de um registro, SWAR, com bits como elementos). (Para projetos recentes da Intel / AMD). Você só precisa descobrir qual bit está desmarcado depois de encontrar o local de 64 bits que o contém. (E, para isso, você podenot / lzcnt
.) É lógico que o loop em um teste de bit único pode não ser otimizado.Como o problema não especifica que precisamos encontrar o menor número possível que não esteja no arquivo, podemos apenas gerar um número maior que o próprio arquivo de entrada. :)
fonte
int
são32
bits, apenas saída2^64-1
. Feito.tr -d '\n' < nums.txt > new_num.txt
:: DPara a variante de 1 GB de RAM, você pode usar um vetor de bits. Você precisa alocar 4 bilhões de bits == 500 MB de matriz de bytes. Para cada número que você lê da entrada, defina o bit correspondente como '1'. Depois de terminar, repita os bits e encontre o primeiro que ainda é '0'. Seu índice é a resposta.
fonte
bitSet.nextClearBit(0)
: download.oracle.com/javase/6/docs/api/java/util/...Se forem números inteiros de 32 bits (provavelmente da escolha de ~ 4 bilhões de números próximos a 2 32 ), sua lista de 4 bilhões de números ocupará no máximo 93% dos números possíveis possíveis (4 * 10 9 / (2 32 ) ) Portanto, se você criar uma matriz de bits de 2 32 bits com cada bit inicializado em zero (que ocupará 2 29 bytes ~ 500 MB de RAM; lembre-se de um byte = 2 3 bits = 8 bits), leia a lista inteira e para cada int, defina o elemento da matriz de bits correspondente de 0 a 1; e depois leia sua matriz de bits e retorne o primeiro bit que ainda é 0.
No caso de você ter menos RAM (~ 10 MB), esta solução precisa ser ligeiramente modificada. 10 MB ~ 83886080 bits ainda são suficientes para fazer uma matriz de bits para todos os números entre 0 e 83886079. Portanto, você pode ler sua lista de entradas; e registre somente #s que estão entre 0 e 83886079 em sua matriz de bits. Se os números são distribuídos aleatoriamente; com probabilidade esmagadora (difere em 100% em cerca de 10 -2592069 ), você encontrará um int ausente. De fato, se você escolher apenas os números de 1 a 2048 (com apenas 256 bytes de RAM), ainda assim encontrará um número ausente em uma porcentagem esmagadora (99,999999999999999999999999999999999999999999999999999999999999995%).
Mas digamos que em vez de ter cerca de 4 bilhões de números; você tinha algo como 2 32 - 1 números e menos de 10 MB de RAM; portanto, qualquer pequena faixa de entradas tem apenas uma pequena possibilidade de não conter o número.
Se você tivesse a garantia de que cada int na lista fosse exclusivo, poderia somar os números e subtrair a soma com um # ausente na soma completa (½) (2 32 ) (2 32 - 1) = 9223372034707292160 para encontrar o int ausente . No entanto, se um int ocorrer duas vezes, esse método falhará.
No entanto, você sempre pode dividir e conquistar. Um método ingênuo seria ler a matriz e contar o número de números que estão na primeira metade (0 a 2 31 -1) e na segunda metade (2 31 , 2 32 ). Em seguida, escolha o intervalo com menos números e repita dividindo esse intervalo ao meio. (Diga se havia dois números a menos em (2 31 , 2 32 ), sua próxima pesquisa contaria os números no intervalo (2 31 , 3 * 2 30 -1), (3 * 2 30 , 2 32 ). repetindo até encontrar um intervalo com número zero e você tiver a sua resposta.Deve levar O (lg N) ~ 32 para ler o array.
Esse método foi ineficiente. Estamos usando apenas dois números inteiros em cada etapa (ou cerca de 8 bytes de RAM com um número inteiro de 4 bytes (32 bits)). Um método melhor seria dividir em sqrt (2 32 ) = 2 16 = 65536 posições, cada uma com 65536 números em uma posição. Cada compartimento requer 4 bytes para armazenar sua contagem, então você precisa de 2 18 bytes = 256 kB. Portanto, o compartimento 0 é (0 a 65535 = 2 16 -1), o compartimento 1 é (2 16 = 65536 a 2 * 2 16 -1 = 131071), o compartimento 2 é (2 * 2 16 = 131072 a 3 * 2 16 - 1 = 196607). Em python, você teria algo como:
Leia a lista inteira de ~ 4 bilhões; e conte quantas polegadas caem em cada uma das 2 16 posições e encontre um incomplete_bin que não tenha todos os números 65536. Então você lê a lista inteira de 4 bilhões novamente; mas desta vez só observe quando números inteiros estão nesse intervalo; lançando um pouco quando você os encontra.
fonte
Por que torná-lo tão complicado? Você pede um número inteiro não presente no arquivo?
De acordo com as regras especificadas, a única coisa que você precisa armazenar é o maior número inteiro encontrado até agora no arquivo. Depois que o arquivo inteiro tiver sido lido, retorne um número 1 maior que isso.
Não há risco de atingir maxint ou algo assim, porque, de acordo com as regras, não há restrição ao tamanho do número inteiro ou ao número retornado pelo algoritmo.
fonte
Isso pode ser resolvido em muito pouco espaço usando uma variante da pesquisa binária.
Comece com o intervalo permitido de números,
0
para4294967295
.Calcule o ponto médio.
Faça um loop pelo arquivo, contando quantos números foram iguais, menores ou maiores que o valor do ponto médio.
Se nenhum número for igual, você está pronto. O número do ponto médio é a resposta.
Caso contrário, escolha o intervalo com menos números e repita o passo 2 com este novo intervalo.
Isso exigirá até 32 verificações lineares no arquivo, mas usará apenas alguns bytes de memória para armazenar o intervalo e as contagens.
Isso é essencialmente o mesmo que a solução de Henning , exceto que ele usa dois compartimentos em vez de 16k.
fonte
EDIT Ok, isso não foi bem pensado, pois assume que os números inteiros no arquivo seguem alguma distribuição estática. Aparentemente, eles não precisam, mas mesmo assim deve-se tentar o seguinte:
Existem .34,3 bilhões de números inteiros de 32 bits. Não sabemos como eles são distribuídos no arquivo, mas o pior caso é aquele com a maior entropia de Shannon: uma distribuição igual. Nesse caso, a probabilidade de um número inteiro não ocorrer no arquivo é
((2³²-1) / 2³²) ⁴ ⁰⁰⁰ ⁰⁰⁰ ⁰⁰⁰ .4
Quanto menor a entropia de Shannon, maior é a probabilidade em média, mas mesmo para o pior dos casos, temos 90% de chance de encontrar um número não-recorrente após 5 tentativas com números inteiros aleatórios. Basta criar esses números com um gerador pseudo-aleatório, armazená-los em uma lista. Em seguida, leia int após int e compare-o com todos os seus palpites. Quando houver uma correspondência, remova esta entrada da lista. Depois de passar por todo o arquivo, é provável que você tenha mais de um palpite. Use qualquer um deles. No evento raro (10%, na pior das hipóteses), sem suposição, obtenha um novo conjunto de números inteiros aleatórios, talvez mais desta vez (10-> 99%).
Consumo de memória: algumas dezenas de bytes, complexidade: O (n), sobrecarga: não aceitável, pois a maior parte do tempo será gasta nos acessos inevitáveis ao disco rígido, em vez de comparar as entradas de qualquer maneira.
O pior caso real, quando não assumimos uma distribuição estática, é que todo número inteiro ocorre no máximo. uma vez, porque somente 1 - 4000000000 / 2³² ≈ 6% de todos os números inteiros não ocorrem no arquivo. Portanto, você precisará de mais palpites, mas isso ainda não custará muito dinheiro.
fonte
Se você tiver um número inteiro ausente no intervalo [0, 2 ^ x - 1], basta xorotá-los todos juntos. Por exemplo:
(Eu sei que isso não responde exatamente à pergunta , mas é uma boa resposta para uma pergunta muito semelhante.)
fonte
0 ^ 1 ^ 3 ^ 4 ^ 6 ^ 7
é 0. [ Escreva 2 x para 2 a x'és de potência e a ^ b para a xor b, o xor de todos os k <2 x é zero - k ^ ~ k = (2 ^ x) - 1 para k <2 ^ (x-1) e k ^ ~ k ^ j ^ ~ j = 0 quando j = k + 2 ** (x-2) - então o xor de todos, exceto um número, é o valor do desaparecido]Eles podem estar olhando para ver se você ouviu falar de um Filtro Bloom probabilístico que pode determinar com muita eficiência absolutamente se um valor não faz parte de um conjunto grande (mas só pode determinar com alta probabilidade que seja um membro do conjunto).
fonte
Com base na redação atual da pergunta original, a solução mais simples é:
Encontre o valor máximo no arquivo e adicione 1 a ele.
fonte
Use a
BitSet
. 4 bilhões de números inteiros (supondo até 2 ^ 32 números inteiros) compactados em um BitSet a 8 por byte é 2 ^ 32/2 ^ 3 = 2 ^ 29 = aproximadamente 0,5 Gb.Para adicionar um pouco mais de detalhe - sempre que você ler um número, defina o bit correspondente no BitSet. Em seguida, passe pelo BitSet para encontrar o primeiro número que não está presente. De fato, você pode fazer isso com a mesma eficácia, escolhendo repetidamente um número aleatório e testando se ele estiver presente.
Na verdade, BitSet.nextClearBit (0) informará o primeiro bit não definido.
Observando a API BitSet, ela parece suportar apenas 0..MAX_INT, portanto, você pode precisar de 2 BitSets - um para números + e cinco e números anteriores - mas os requisitos de memória não mudam.
fonte
BitSet
... tente uma matriz de bits. Faz a mesma coisa;)Se não houver limite de tamanho, a maneira mais rápida é obter o tamanho do arquivo e gerar o tamanho do arquivo + 1 número de dígitos aleatórios (ou apenas "11111 ..." s). Vantagem: você nem precisa ler o arquivo e pode minimizar o uso de memória quase até zero. Desvantagem: você imprimirá bilhões de dígitos.
No entanto, se o único fator estivesse minimizando o uso da memória e nada mais for importante, essa seria a solução ideal. Pode até dar a você o prêmio de "pior abuso das regras".
fonte
Se assumirmos que o intervalo de números sempre será 2 ^ n (uma potência par de 2), então exclusivo - ou funcionará (como mostrado em outro pôster). Quanto ao motivo, vamos provar:
A teoria
Dado qualquer intervalo de inteiros baseado em 0 que tenha
2^n
elementos com um elemento ausente, você pode encontrar esse elemento faltante simplesmente xorando os valores conhecidos juntos para gerar o número ausente.A prova
Vejamos n = 2. Para n = 2, podemos representar 4 números inteiros únicos: 0, 1, 2, 3. Eles têm um padrão de bits de:
Agora, se olharmos, cada bit é definido exatamente duas vezes. Portanto, uma vez que é definido um número par de vezes, e exclusivo - ou dos números produzirá 0. Se um único número estiver ausente, o exclusivo - ou produzirá um número que, quando exclusivo com o número ausente, resultará em 0. Portanto, o número ausente e o número exclusivo ored resultante são exatamente iguais. Se removermos 2, o xor resultante será
10
(ou 2).Agora, vejamos n + 1. Vamos ligar para o número de vezes que cada bit é definido em
n
,x
eo número de vezes que cada bit é definido non+1
y
. O valor dey
será igual a,y = x * 2
porque existemx
elementos com on+1
bit definido como 0 ex
elementos com on+1
bit definido como 1. E, como2x
sempre será par,n+1
sempre terá cada bit definido um número par de vezes.Portanto, como
n=2
funciona en+1
funciona, o método xor funcionará para todos os valores den>=2
.O algoritmo para intervalos baseados em 0
Isto é bem simples. Ele usa 2 * n bits de memória, portanto, para qualquer intervalo <= 32, 2 inteiros de 32 bits funcionarão (ignorando qualquer memória consumida pelo descritor de arquivo). E faz uma única passagem do arquivo.
O algoritmo para intervalos arbitrários
Esse algoritmo funcionará para intervalos de qualquer número inicial a qualquer número final, contanto que o intervalo total seja igual a 2 ^ n ... através do arquivo (o primeiro a obter o mínimo, o segundo a calcular o int ausente).
Intervalos arbitrários
Podemos aplicar esse método modificado a um conjunto de intervalos arbitrários, pois todos os intervalos cruzarão uma potência de 2 ^ n pelo menos uma vez. Isso funciona apenas se houver um único bit ausente. São necessárias duas passagens de um arquivo não classificado, mas ele sempre encontrará o número ausente:
Basicamente, baseia novamente o intervalo em torno de 0. Em seguida, conta o número de valores não classificados a serem acrescentados enquanto calcula o exclusivo-ou. Em seguida, adiciona 1 à contagem de valores não classificados para cuidar do valor ausente (conte o valor ausente). Em seguida, continue xorando o valor n, incrementado em 1 a cada vez até que n seja uma potência de 2. O resultado será então baseado novamente na base original. Feito.
Aqui está o algoritmo que testei em PHP (usando uma matriz em vez de um arquivo, mas o mesmo conceito):
Alimentado em uma matriz com qualquer faixa de valores (eu testei incluindo negativos) com uma dentro dessa faixa que está faltando, ele encontrou o valor correto a cada vez.
Outra abordagem
Como podemos usar a classificação externa, por que não apenas verificar uma lacuna? Se assumirmos que o arquivo está classificado antes da execução desse algoritmo:
fonte
sum(0..n) = n*(n+1)/2
. Entãomissing = nmax*(nmax+1)/2 - nmin*(nmin+1)/2 - sum(input[])
. (ideia soma da resposta de @ Hammar.)Truque de pergunta, a menos que tenha sido citado incorretamente. Basta ler o arquivo uma vez para obter o número inteiro máximo
n
e retornarn+1
.É claro que você precisaria de um plano de backup, caso
n+1
cause um estouro de número inteiro.fonte
Verifique o tamanho do arquivo de entrada e, em seguida, imprima qualquer número que seja muito grande para ser representado por um arquivo desse tamanho. Isso pode parecer um truque barato, mas é uma solução criativa para um problema de entrevista, claramente evita o problema de memória e, tecnicamente, O (n).
Deve imprimir 10 bits - 1 , que sempre será maior que 2 bits . Tecnicamente, o número que você precisa vencer é de 2 bits - (4 * 10 9 - 1) , pois você sabe que existem (4 bilhões - 1) outros números inteiros no arquivo e, mesmo com a compactação perfeita, eles ocupam pelo menos um pouco cada.
fonte
Console.Write( 1 << bitcount )
vez do loop? Se houver n bits no arquivo, qualquer número de bits (_n_ + 1) com um 1 à esquerda é absolutamente garantido como maior.<<
operador. De qualquer forma, a menos que você role seu próprio tipo inteiro gigantesco, será um tamanho de arquivo muito pequeno. Demo: rextester.com/BLETJ59067A abordagem mais simples é encontrar o número mínimo no arquivo e retornar 1 a menos que isso. Isso usa armazenamento O (1) e tempo O (n) para um arquivo de n números. No entanto, ele falhará se o intervalo de números for limitado, o que pode fazer com que min-1 não seja um número.
O método simples e direto de usar um bitmap já foi mencionado. Esse método usa O (n) tempo e armazenamento.
Um método de 2 passagens com 2 ^ 16 baldes de contagem também foi mencionado. Ele lê 2 * n inteiros, portanto, usa O (n) time e O (1) de armazenamento, mas não pode manipular conjuntos de dados com mais de 2 ^ 16 números. No entanto, é facilmente estendido para (por exemplo) 2 ^ 60 números inteiros de 64 bits executando 4 passagens em vez de 2 e adaptado facilmente ao uso de memória minúscula, usando apenas o número de posições necessárias na memória e aumentando o número de passagens correspondentemente, em Nesse caso, o tempo de execução não é mais O (n), mas sim O (n * log n).
O método de XOR'inging todos os números juntos, mencionados até agora por rfrankel e longamente por ircmaxell responde à pergunta feita no stackoverflow # 35185 , como ltn100 apontou. Ele usa O (1) armazenamento e O (n) tempo de execução. Se por enquanto assumimos números inteiros de 32 bits, o XOR tem 7% de probabilidade de produzir um número distinto. Justificativa: dado ~ 4G números distintos XOR'd juntos, e ca. 300M fora do arquivo, o número de bits definidos em cada posição de bit tem chances iguais de serem ímpares ou pares. Assim, 2 ^ 32 números têm a mesma probabilidade de surgir que o resultado XOR, dos quais 93% já estão no arquivo. Observe que, se os números no arquivo não forem todos distintos, a probabilidade de sucesso do método XOR aumentará.
fonte
Por alguma razão, assim que li esse problema, pensei em diagonalização. Estou assumindo números inteiros arbitrariamente grandes.
Leia o primeiro número. Deixe o teclado esquerdo com zero bits até você ter 4 bilhões de bits. Se o primeiro bit (de ordem superior) for 0, saída 1; else output 0. (Você realmente não precisa usar o teclado esquerdo: você apenas gera 1 se não houver bits suficientes no número.) Faça o mesmo com o segundo número, exceto usar o segundo bit. Continue com o arquivo dessa maneira. Você produzirá um número de 4 bilhões de bits, um bit de cada vez, e esse número não será o mesmo que o existente no arquivo. Prova: era o mesmo número enésimo, então eles concordariam com o enésimo bit, mas não por construção.
fonte
i
th bit, você pode gerar 1 bit 4 bilhões de vezes e lançar 1 extra no final. Eu estou bem com ter números inteiros arbitrariamente grandes no algoritmo, mas acho que o problema é gerar um número inteiro de 32 bits ausente. Simplesmente não faz sentido de outra maneira.Você pode usar sinalizadores de bit para marcar se um número inteiro está presente ou não.
Depois de percorrer o arquivo inteiro, verifique cada bit para determinar se o número existe ou não.
Supondo que cada número inteiro seja 32 bits, eles caberão convenientemente em 1 GB de RAM se a sinalização de bit for concluída.
fonte
Do Reddit por Carbonetc.
fonte
Apenas por uma questão de integridade, aqui está outra solução muito simples, que provavelmente levará muito tempo para ser executada, mas usa muito pouca memória.
Permita que todos os números inteiros possíveis sejam o intervalo de
int_min
atéint_max
ebool isNotInFile(integer)
uma função que retorne true se o arquivo não contiver um determinado número inteiro e false mais (comparando esse número inteiro com cada número inteiro no arquivo)fonte
isNotInFile
função. Certifique-se de entender a pergunta antes de responder.Para a restrição de memória de 10 MB:
Quando terminar, basta seguir um caminho que não foi criado antes para criar o número solicitado.
Número de 4 bilhões = 2 ^ 32, o que significa que 10 MB podem não ser suficientes.
EDITAR
Uma otimização é possível, se duas folhas de extremidade tiverem sido criadas e tiverem um pai comum, elas poderão ser removidas e o pai sinalizado como não uma solução. Isso corta ramificações e reduz a necessidade de memória.
EDIT II
Não há necessidade de construir a árvore completamente também. Você só precisará criar ramificações profundas se os números forem semelhantes. Se também cortamos galhos, essa solução pode funcionar de fato.
fonte
Vou responder a versão de 1 GB:
Não há informações suficientes na pergunta, então vou declarar algumas suposições primeiro:
O número inteiro é 32 bits com intervalo -2.147.483.648 a 2.147.483.647.
Pseudo-código:
fonte
Enquanto estivermos dando respostas criativas, aqui está outra.
Use o programa de classificação externa para classificar o arquivo de entrada numericamente. Isso funcionará para qualquer quantidade de memória que você tenha (ele usará o armazenamento de arquivos, se necessário). Leia o arquivo classificado e produza o primeiro número que está faltando.
fonte
Eliminação de bits
Uma maneira é eliminar bits, no entanto, isso pode realmente não resultar em um resultado (é provável que não ocorra). Psuedocode:
Contagens de bits
Acompanhe as contagens de bits; e use os bits com as menores quantidades para gerar um valor. Novamente, isso não tem garantia de gerar um valor correto.
Range Logic
Acompanhe os intervalos ordenados de uma lista (ordenados pelo início). Um intervalo é definido pela estrutura:
Passe por cada valor no arquivo e tente removê-lo do intervalo atual. Este método não tem garantias de memória, mas deve funcionar muito bem.
fonte
2 128 * 10 18 + 1 (que é (2 8 ) 16 * 10 18 + 1) - não pode ser uma resposta universal para hoje? Isso representa um número que não pode ser mantido no arquivo 16 EB, que é o tamanho máximo do arquivo em qualquer sistema de arquivos atual.
fonte
Acho que esse é um problema resolvido (veja acima), mas há um caso secundário interessante a ser lembrado, pois pode ser perguntado:
Se houver exatamente 4.294.967.295 (2 ^ 32 - 1) números inteiros de 32 bits sem repetições e, portanto, apenas um estiver faltando, haverá uma solução simples.
Inicie um total em execução em zero e, para cada número inteiro no arquivo, adicione esse número inteiro com estouro de 32 bits (efetivamente, runningTotal = (runningTotal + nextInteger)% 4294967296). Depois de concluído, adicione 4294967296/2 ao total em execução, novamente com estouro de 32 bits. Subtraia isso de 4294967296 e o resultado será o número inteiro ausente.
O problema "apenas um número inteiro ausente" é solucionável com apenas uma execução e apenas 64 bits de RAM dedicados aos dados (32 para o total em execução, 32 para leitura no próximo número inteiro).
Corolário: A especificação mais geral é extremamente simples de corresponder se não estivermos preocupados com quantos bits o resultado inteiro deve ter. Nós apenas geramos um número inteiro grande o suficiente para que ele não possa estar contido no arquivo que recebemos. Novamente, isso ocupa uma quantidade mínima de RAM. Veja o pseudocódigo.
fonte
Como Ryan disse basicamente, classifique o arquivo e repasse os números inteiros e quando um valor for ignorado, você o terá :)
EDITAR em downvoters: o OP mencionou que o arquivo poderia ser classificado, portanto este é um método válido.
fonte
Se você não assumir a restrição de 32 bits, basta retornar um número de 64 bits gerado aleatoriamente (ou 128 bits, se você for pessimista). A chance de colisão é
1 in 2^64/(4*10^9) = 4611686018.4
(aproximadamente 1 em 4 bilhões). Você estaria certo na maioria das vezes!(Brincando ... mais ou menos.)
fonte