A tarefa é claramente encontrar um algoritmo que seja O (1) no comprimento N da lista de números necessária. Portanto, não importa se você precisa do número 100 ou 10000, o tempo de inserção deve ser O (1).
O truque aqui é que, embora esse requisito O (1) seja mencionado na inserção da lista, a pergunta não disse nada sobre a ordem do tempo de pesquisa no espaço numérico inteiro, mas acontece que isso pode ser feito O (1) também. A solução é a seguinte:
Organize uma hashtable com números para chaves e pares de ponteiros de lista vinculada para valores. Cada par de ponteiros é o início e o fim de uma sequência de lista vinculada. Normalmente, este será apenas um elemento e depois o próximo. Cada elemento da lista vinculada fica próximo ao elemento com o próximo número mais alto. Portanto, a lista vinculada contém a sequência classificada dos números obrigatórios. Mantenha um registro do número mais baixo.
Pegue um novo número x do fluxo aleatório.
É superior ao último número mais baixo registrado? Sim => Etapa 4, Não => Etapa 2
Bata na tabela de hash com o número acabado de obter. Existe uma entrada? Sim => Etapa 5. Não => Pegue um novo número x-1 e repita esta etapa (esta é uma pesquisa linear descendente simples, aceite aqui, isso pode ser melhorado e eu explicarei como)
Com o elemento list obtido apenas na tabela de hash, insira o novo número logo após o elemento na lista vinculada (e atualize o hash)
Pegue o número mais baixo l registrado (e remova-o da lista / hash).
Bata na tabela de hash com o número acabado de obter. Existe uma entrada? Sim => Etapa 8. Não => Pegue um novo número l + 1 e repita esta etapa (esta é uma pesquisa linear ascendente simples)
Com um acerto positivo, o número se torna o novo número mais baixo. Avance para o passo 2
Para permitir valores duplicados, o hash realmente precisa manter o início e o fim da sequência de lista vinculada de elementos duplicados. Adicionar ou remover um elemento em uma determinada tecla aumenta ou diminui o intervalo apontado.
A inserção aqui é O (1). As pesquisas mencionadas são, acho que algo como, O (diferença média entre números). A diferença média aumenta com o tamanho do espaço numérico, mas diminui com o comprimento necessário da lista de números.
Portanto, a estratégia de pesquisa linear é muito ruim, se o espaço numérico for grande (por exemplo, para um tipo int de 4 bytes, 0 a 2 ^ 32-1) e N = 100. Para contornar esse problema de desempenho, você pode manter conjuntos paralelos de tabelas de hash, onde os números são arredondados para magnitudes mais altas (por exemplo, 1s, 10s, 100s, 1000s) para criar as teclas adequadas. Dessa forma, você pode acelerar e diminuir as marchas para realizar as pesquisas necessárias mais rapidamente. O desempenho então se torna um O (log numberrange), eu acho, que é constante, ou seja, O (1) também.
Para deixar isso mais claro, imagine que você tenha o número 197 em mãos. Você atinge a tabela de hash 10s, com '190', é arredondado para o próximo dez. Qualquer coisa? Não. Então você diminui em 10s até pressionar, digamos, 120. Então você pode começar em 129 na hashtable 1s e tentar 128, 127 até atingir alguma coisa. Agora você encontrou o local na lista vinculada para inserir o número 197. Ao inseri-lo, você também deve atualizar a hashtable 1s com a entrada 197, a hashtable 10s com o número 190, 100s com 100, etc. o que você precisa fazer aqui é 10 vezes o log do intervalo de números.
Talvez eu tenha entendido errado alguns detalhes, mas como essa é a troca de programadores e o contexto foi de entrevistas, espero que o texto acima seja uma resposta suficientemente convincente para essa situação.
EDIÇÃO Adicionei alguns detalhes extras aqui para explicar o esquema de hashtable paralelo e como isso significa que as pesquisas lineares ruins que eu mencionei podem ser substituídas por uma pesquisa O (1). Também percebi que, obviamente, não há necessidade de procurar o próximo número mais baixo, porque você pode ir direto para ele procurando na hashtable com o número mais baixo e progredindo para o próximo elemento.