Ouvi muito essa pergunta da entrevista e esperava obter algumas opiniões sobre quais seriam as boas respostas: você tem um arquivo grande com mais de 10 GB e deseja descobrir qual elemento ocorre mais, qual é uma boa maneira para fazer isso?
Iterar e acompanhar um mapa provavelmente não é uma boa ideia, pois você usa muita memória, e acompanhar as entradas não é a melhor opção, pois quando essa pergunta é feita, o arquivo geralmente já existe.
Outros pensamentos que eu incluí incluem dividir o arquivo para ser iterado e processado por vários threads e depois ter esses resultados combinados, mas o problema de memória para os mapas ainda está lá.
algorithms
arrays
Pat
fonte
fonte
Respostas:
Quando você tem um arquivo muito grande e muitos elementos, mas o elemento mais comum é muito comum - ocorre fração do tempo - você pode encontrá-lo em tempo linear com palavras O ( k ) de espaço (o A constante na notação O ( ) é muito pequena, basicamente 2 se você não contar o armazenamento para itens auxiliares como hash). Além disso, isso funciona muito bem com armazenamento externo, pois o arquivo é processado em sequência, um elemento de cada vez, e o algoritmo nunca "olha para trás". Uma maneira de fazer isso é através de um algoritmo clássico de Misra e Gries, veja estas notas de aula> 1 / k O ( k ) O ( ) . O problema agora é conhecido como problema dos rebatedores pesados (os elementos frequentes são os rebatedores pesados).
A suposição de que o elemento mais frequente aparece fração do tempo para k um número pequeno pode parecer forte, mas é de certa forma necessário! Ou seja, se você tiver acesso seqüencial ao seu arquivo (e caso o arquivo seja enorme, o acesso aleatório será muito caro), qualquer algoritmo que sempre encontre o elemento mais frequente em um número constante de passes utilizará espaço linear no número de elementos . Portanto, se você não assume algo sobre a entrada, não pode vencer uma tabela de hash. A suposição de que o elemento mais frequente é muito frequente talvez seja a maneira mais natural de contornar os resultados negativos.> 1 / k k
Aqui está um esboço para , ou seja, quando existe um único elemento que ocorre mais da metade do tempo. Esse caso especial é conhecido como algoritmo de votação majoritária e é devido a Boyer e Moore. Manteremos um único elemento e uma única contagem. Inicialize a contagem para 1 e armazene o primeiro elemento do arquivo. Em seguida, processe o arquivo em sequência:k = 2
Um pouco de reflexão sobre este procedimento o convencerá de que, se existir um elemento "majoritário", ou seja, um que ocorra mais da metade do tempo, esse elemento será o elemento armazenado após o processamento do arquivo inteiro.
Para geral , você mantém k - 1k k - 1 elementos e contagens e inicializa os elementos nos primeiros k elementos distintos do arquivo e as contagens no número de vezes que cada um desses elementos aparece antes de ver k- ésimo elemento distinto. Em seguida, você executa essencialmente o mesmo procedimento: a contagem de um elemento é aumentada cada vez que é encontrada, todas as contagens de elementos são diminuídas se um elemento que não é armazenado for encontrado e, quando alguma contagem for zero, esse elemento será expulso em favor do elemento. elemento atual do arquivo. Este é o algoritmo de Misra-Gries.k - 1 k k
Obviamente, você pode usar uma tabela de hash para indexar ok - 1 1 / k O ( k )
Uma coisa final: depois de encontrar candidato "hitters pesados" (ou seja, elementos frequentes), você pode fazer mais uma passagem sobre o arquivo para contar a frequência de cada elemento. Dessa forma, você pode classificar os elementos entre si e verificar se todos eles ocorrem mais de 1k 1 / k k - 1
fonte
A resposta óbvia é, obviamente, manter um mapa de hash e armazenar um contador da ocorrência de elementos à medida que você percorre o arquivo, como Nejc já sugeriu. Essa é (em termos de complexidade de tempo) a solução ideal.
fonte
Se o elemento mais comum for mais comum do que o próximo por uma margem substancial e o número de elementos diferentes for pequeno comparado ao tamanho do arquivo, você poderá amostrar aleatoriamente alguns elementos e retornar o elemento mais comum em sua amostra.
fonte