Esse problema me foi dado em uma entrevista. Como você responderia?
Projete uma estrutura de dados que ofereça as seguintes operações em tempo O (1):
- inserir
- remover
- contém
- obter elemento aleatório
data-structures
florim
fonte
fonte
Respostas:
Considere uma estrutura de dados composta de uma hashtable H e um array A. As chaves hashtable são os elementos na estrutura de dados e os valores são suas posições no array.
como a matriz precisa aumentar automaticamente de tamanho, será amortizado O (1) para adicionar um elemento, mas acho que está tudo bem.
fonte
O (1) lookup implica uma estrutura de dados hash .
Por comparação:
fonte
hashtable.get((int)(Math.random()*hashtable.size()));
Você pode não gostar disso, porque eles provavelmente estão procurando por uma solução inteligente, mas às vezes vale a pena se ater a suas armas ... Uma tabela hash já satisfaz os requisitos - provavelmente melhor do que qualquer outra coisa (embora obviamente em constante amortizada tempo, e com compromissos diferentes para outras soluções).
O requisito que é complicado é a seleção de "elemento aleatório": em uma tabela hash, você precisaria fazer a varredura ou sondar esse elemento.
Para hashing fechado / endereçamento aberto, a chance de qualquer depósito ser ocupado é
size() / capacity()
, mas crucialmente isso é normalmente mantido em um intervalo multiplicativo constante por uma implementação de tabela hash (por exemplo, a tabela pode ser mantida maior do que seu conteúdo atual, digamos 1,2x para ~ 10x dependendo do desempenho / ajuste de memória). Isso significa que, em média, podemos esperar pesquisar 1,2 a 10 baldes - totalmente independente do tamanho total do contêiner; amortizado O (1).Posso imaginar duas abordagens simples (e muitas outras muito mais complicadas):
pesquisar linearmente de um balde aleatório
tente baldes aleatórios repetidamente até encontrar um preenchido
Não é uma ótima solução, mas ainda pode ser um compromisso geral melhor do que as sobrecargas de memória e desempenho de manter um segundo array de índice o tempo todo.
fonte
A melhor solução é provavelmente o hash table + array, é bem rápido e determinístico.
Mas a resposta com a pontuação mais baixa (apenas use uma tabela hash!) Também é ótima!
As pessoas podem não gostar disso por causa de "possíveis loops infinitos", e eu já vi pessoas muito inteligentes terem essa reação também, mas é errado! Eventos infinitamente improváveis simplesmente não acontecem.
Presumindo o bom comportamento de sua fonte pseudo-aleatória - o que não é difícil de estabelecer para este comportamento específico - e que as tabelas hash estão sempre pelo menos 20% cheias, é fácil ver que:
Ele vai não acontecer que getRandom () tem que tentar mais de 1000 vezes. Apenas nunca . Na verdade, a probabilidade de tal evento é 0,8 ^ 1000, que é 10 ^ -97 - então teríamos que repeti-lo 10 ^ 88 vezes para ter uma chance em um bilhão de acontecer uma vez. Mesmo que este programa funcionasse em tempo integral em todos os computadores da humanidade até a morte do Sol, isso nunca acontecerá.
fonte
Para esta questão, usarei duas estruturas de dados
Passos :-
Código: -
- Complexidade de tempo O (1). - Complexidade do espaço O (N).
fonte
Aqui está uma solução em C # para o problema que eu propus há pouco tempo, quando fiz a mesma pergunta. Ele implementa Add, Remove, Contains e Random junto com outras interfaces .NET padrão. Não que você precise implementá-lo com tantos detalhes durante uma entrevista, mas é bom ter uma solução concreta para olhar ...
fonte
ArgumentException
com a mensagem "Um item com a mesma chave já foi adicionado." será lançado (do Dicionário de índice subjacente).Podemos usar hashing para dar suporte a operações em tempo Θ (1).
insert (x) 1) Verifique se x já está presente fazendo uma pesquisa de mapa hash. 2) Se não estiver presente, insira-o no final da matriz. 3) Adicione também a tabela hash, x é adicionado como chave e o último índice da matriz como índice.
remove (x) 1) Verifique se x está presente fazendo uma pesquisa de mapa hash. 2) Se estiver presente, encontre seu índice e remova-o do mapa hash. 3) Troque o último elemento por este elemento na matriz e remova o último elemento. A troca é feita porque o último elemento pode ser removido no tempo O (1). 4) Atualize o índice do último elemento no mapa hash.
getRandom () 1) Gere um número aleatório de 0 ao último índice. 2) Retorne o elemento da matriz no índice gerado aleatoriamente.
search (x) Faça uma busca por x no mapa hash.
fonte
Embora isso seja muito antigo, mas como não há resposta em C ++, aqui estão meus dois centavos.
Aqui está uma parte do código do cliente para testar a solução.
fonte
No C # 3.0 + .NET Framework 4, um genérico
Dictionary<TKey,TValue>
é ainda melhor do que um Hashtable porque você pode usar oSystem.Linq
método de extensãoElementAt()
para indexar na matriz dinâmica subjacente onde osKeyValuePair<TKey,TValue>
elementos são armazenados:No entanto, até onde eu sei, uma Hashtable (ou sua progênie de Dicionário) não é uma solução real para este problema porque Put () só pode ser amortizado O (1), não verdadeiro O (1), porque é O (N ) no limite de redimensionamento dinâmico.
Existe uma solução real para este problema? Tudo o que posso pensar é que se você especificar a capacidade inicial de um Dicionário / Hashtable em uma ordem de magnitude além do que você antecipa que vai precisar, então você obtém operações O (1) porque nunca precisa redimensionar.
fonte
Eu concordo com Anon. Exceto para o último requisito em que é necessário obter um elemento aleatório com igual justiça, todos os outros requisitos podem ser tratados apenas usando um único DS baseado em Hash. Vou escolher HashSet para isso em Java. O módulo do código hash de um elemento me dará o número do índice da matriz subjacente no tempo O (1). Posso usar isso para adicionar, remover e conter operações.
fonte
Não podemos fazer isso usando HashSet de Java? Ele fornece insert, del, search all in O (1) por padrão. Para getRandom, podemos fazer uso do iterador de Set que, de qualquer maneira, fornece comportamento aleatório. Podemos apenas iterar o primeiro elemento do conjunto sem nos preocupar com o resto dos elementos
fonte
fonte
Por que não usamos epoch% arraysize para encontrar o elemento aleatório. Encontrar o tamanho do array é O (n), mas a complexidade amortizada será O (1).
fonte
Acho que podemos usar a lista de links duplamente com tabela de hash. a chave será o elemento e seu valor associado será o nó na lista de links dupla.
fonte