Recentemente, participei de uma entrevista na qual me pediram "escreva um programa para encontrar os 100 maiores números de uma matriz de 1 bilhão de números".
Eu só consegui fornecer uma solução de força bruta que classificasse a matriz na complexidade de tempo O (nlogn) e levasse os últimos 100 números.
Arrays.sort(array);
O entrevistador estava procurando uma complexidade de tempo melhor. Tentei outras soluções, mas não consegui responder. Existe uma solução melhor para a complexidade do tempo?
O(1)
neste caso, porque não há aumento de dimensão. O entrevistador deveria ter perguntado "Como encontrar m maiores elementos de uma matriz de n com n >> m?".Respostas:
Você pode manter uma fila prioritária dos 100 maiores números, percorrer os bilhões de números, sempre que encontrar um número maior que o menor número da fila (a cabeça da fila), remover a cabeça da fila e adicionar o novo número para a fila.
EDIT: como Dev observou, com uma fila de prioridade implementada com um heap, a complexidade da inserção na fila é
O(logN)
No pior dos casos, você obtém o que é melhor do que
billionlog2(100)
billion
log2(billion)
Em geral, se você precisar dos maiores números K de um conjunto de N números, a complexidade é
O(NlogK)
mais do queO(NlogN)
isso pode ser muito significativo quando K for muito pequeno comparado a N.EDIT2:
O tempo esperado desse algoritmo é bastante interessante, pois em cada iteração uma inserção pode ou não ocorrer. A probabilidade do i-ésimo número a ser inserido na fila é a probabilidade de uma variável aleatória ser maior que pelo menos
i-K
variáveis aleatórias da mesma distribuição (os primeiros k números são adicionados automaticamente à fila). Podemos usar estatísticas de pedidos (veja o link ) para calcular essa probabilidade. Por exemplo, vamos assumir que os números foram selecionados aleatoriamente de maneira uniforme{0, 1}
, o valor esperado de (iK) o número (de i números) é(i-k)/i
e a chance de uma variável aleatória ser maior que esse valor1-[(i-k)/i] = k/i
.Assim, o número esperado de inserções é:
E o tempo de execução esperado pode ser expresso como:
(
k
tempo para gerar a fila com os primeirosk
elementos,n-k
comparações e o número esperado de inserções, conforme descrito acima, cada um leva umlog(k)/2
tempo médio )Observe que quando
N
é muito grande em comparação comK
, essa expressão está muito mais próximan
e nãoNlogK
. Isso é um pouco intuitivo, como no caso da pergunta, mesmo após 10000 iterações (que é muito pequena em comparação a um bilhão), a chance de um número ser inserido na fila é muito pequena.fonte
k
constante e pequeno em comparação comn
. Porém, é preciso sempre ter em mente essas "circunstâncias normais".Se isso for perguntado em uma entrevista, acho que o entrevistador provavelmente deseja ver seu processo de solução de problemas, não apenas seu conhecimento de algoritmos.
A descrição é bastante geral, então talvez você possa perguntar a ele o alcance ou o significado desses números para esclarecer o problema. Fazer isso pode impressionar um entrevistador. Se, por exemplo, esses números representam a idade das pessoas dentro de um país (por exemplo, China), é um problema muito mais fácil. Com uma suposição razoável de que ninguém vivo tem mais de 200 anos, você pode usar uma matriz int de tamanho 200 (talvez 201) para contar o número de pessoas com a mesma idade em apenas uma iteração. Aqui, o índice significa a idade. Depois disso, é fácil encontrar o número 100 maior. A propósito, esse algo é chamado de contagem de contagem .
De qualquer forma, tornar a pergunta mais específica e clara é boa para você em uma entrevista.
fonte
Você pode iterar sobre os números que levam O (n)
Sempre que você encontrar um valor maior que o mínimo atual, adicione o novo valor a uma fila circular com tamanho 100.
O minuto dessa fila circular é o seu novo valor de comparação. Continue adicionando a essa fila. Se cheio, extraia o mínimo da fila.
fonte
Percebi que isso está marcado com 'algoritmo', mas descartará outras opções, pois provavelmente também deve estar marcado com 'entrevista'.
Qual é a fonte dos 1 bilhão de números? Se for um banco de dados, 'selecionar valor da ordem da tabela pelo valor desc limite 100' faria o trabalho muito bem - pode haver diferenças de dialeto.
Isso é único, ou algo que será repetido? Se repetido, com que frequência? Se for único e os dados estiverem em um arquivo, 'cat srcfile | ordenar (opções conforme necessário) | O cabeçalho -100 'fará com que você faça rapidamente um trabalho produtivo que será pago enquanto o computador lida com essa tarefa trivial.
Se repetir, você recomendaria escolher uma abordagem decente para obter a resposta inicial e armazenar / armazenar em cache os resultados, para que você pudesse continuamente reportar os 100 melhores.
Finalmente, há essa consideração. Você está procurando um emprego básico e entrevistando um gerente nerd ou futuro colega de trabalho? Nesse caso, você pode descartar todo tipo de abordagem que descreva os prós e contras técnicos relativos. Se você estiver procurando por um trabalho mais gerencial, faça-o como um gerente, preocupado com os custos de desenvolvimento e manutenção da solução, diga "muito obrigado" e saia, se esse for o entrevistador que deseja se concentrar nas curiosidades da CS . É improvável que ele e você tenham muito potencial de progresso lá.
Melhor sorte na próxima entrevista.
fonte
Minha reação imediata a isso seria usar uma pilha, mas há uma maneira de usar o QuickSelect sem manter todos os valores de entrada em mãos a qualquer momento.
Crie uma matriz de tamanho 200 e preencha-a com os primeiros 200 valores de entrada. Execute o QuickSelect e descarte os 100 baixos, deixando-o com 100 lugares gratuitos. Leia os próximos 100 valores de entrada e execute o QuickSelect novamente. Continue até ter executado a entrada inteira em lotes de 100.
No final, você tem os 100 principais valores. Para valores N, você executou o QuickSelect aproximadamente N / 100 vezes. Cada Quickselect custa cerca de 200 vezes uma constante, portanto, o custo total é 2N vezes uma constante. Isso parece linear no tamanho da entrada para mim, independentemente do tamanho do parâmetro que eu estou conectando para ser 100 nesta explicação.
fonte
partial_sort
execução do libstdc ++ diretamente em um conjunto de dados de 200 milhões de 32 bitsint
(criado por meio de um MT19937, distribuído uniformemente).Ordering.greatestOf(Iterable, int)
faz. É absolutamente linear-time e single-pass, e é um algoritmo super fofo. FWIW, também temos algumas referências reais: seus fatores constantes são um pouco mais lentos do que a fila de prioridade tradicional no caso médio, mas essa implementação é muito mais resistente à entrada do "pior caso" (por exemplo, entrada estritamente ascendente).Você pode usar o algoritmo de seleção rápida para encontrar o número no índice (por ordem) [bilhões-101] e, em seguida, iterar sobre os números e encontrar os números que são maiores a partir desse número.
Este algoritmo Tempo é: 2 XO (N) = O (N) (desempenho médio do caso)
A segunda opção, como sugerida por Thomas Jungblut, é:
Use o Heap ao criar o heap MAX, que receberá O (N) e, em seguida, os 100 números máximos máximos estarão no topo do Heap. Tudo o que você precisa é tirá-los do heap (100 XO (Log (N)).
Este algoritmo Tempo é: O (N) + 100 XO (Log (N)) = O (N)
fonte
O(N)
, realizar duas QuickSelects e outra verificação linear é muito mais caro do que o necessário.100*O(N)
(se isso é uma sintaxe válida) =O(100*N)
=O(N)
(é certo que 100 pode ser variável; nesse caso, isso não é estritamente verdadeiro). Ah, e o Quickselect tem o pior desempenho de O (N ^ 2) (ai). E se não couber na memória, você recarregará os dados do disco duas vezes, o que é muito pior que uma vez (esse é o gargalo).Embora a outra solução de seleção rápida tenha sido rebaixada, o fato é que a seleção rápida encontrará a solução mais rapidamente do que usando uma fila de tamanho 100. O Quickselect tem um tempo de execução esperado de 2n + o (n), em termos de comparações. Uma implementação muito simples seria
Isso levará 3n + o (n) comparações em média. Além disso, pode ser mais eficiente usando o fato de que a seleção rápida deixará os 100 maiores itens da matriz nos 100 locais mais à direita. Portanto, o tempo de execução pode ser aprimorado para 2n + o (n).
Existe o problema de que esse tempo de execução é esperado, e não o pior caso, mas usando uma estratégia de seleção de pivô decente (por exemplo, escolha 21 elementos aleatoriamente e escolha a mediana desses 21 como pivô), o número de comparações poderá ser garantido com alta probabilidade de ser no máximo (2 + c) n para uma constante arbitrariamente pequena c.
De fato, usando uma estratégia de amostragem otimizada (por exemplo, elementos sqrt (n) de amostra aleatoriamente e escolha o 99º percentil), o tempo de execução pode ser reduzido para (1 + c) n + o (n) para c arbitrariamente pequeno (assumindo que K, o número de elementos a serem selecionados é o (n)).
Por outro lado, o uso de uma fila de tamanho 100 exigirá comparações O (log (100) n) e a base de log 2 de 100 é aproximadamente igual a 6,6.
Se pensarmos nesse problema no sentido mais abstrato de escolher os maiores elementos K de uma matriz de tamanho N, onde K = o (N), mas K e N vão para o infinito, o tempo de execução da versão de seleção rápida será O (N) e a versão da fila serão O (N log K), portanto, nesse sentido, a seleção rápida também é assintoticamente superior.
Nos comentários, foi mencionado que a solução da fila será executada no tempo esperado N + K log N em uma entrada aleatória. Evidentemente, a suposição de entrada aleatória nunca é válida, a menos que a pergunta indique explicitamente. A solução de fila pode ser feita para atravessar a matriz em uma ordem aleatória, mas isso implicará o custo adicional de chamadas N para um gerador de números aleatórios, além de permitir toda a matriz de entrada ou alocar uma nova matriz de comprimento N contendo o índices aleatórios.
Se o problema não permitir que você se mova pelos elementos da matriz original, e o custo da alocação de memória for alto, a duplicação da matriz não é uma opção, isso é outra questão. Mas estritamente em termos de tempo de execução, esta é a melhor solução.
fonte
pegue os 100 primeiros números do bilhão e ordene-os. agora basta percorrer o bilhão, se o número de origem for maior que o menor de 100, insira na ordem de classificação. Você termina com algo muito mais próximo de O (n) sobre o tamanho do conjunto.
fonte
Duas opções:
(1) Heap (priorityQueue)
Mantenha um min-heap com tamanho de 100. Atravesse a matriz. Quando o elemento for menor que o primeiro elemento no heap, substitua-o.
(2) Modelo de redução de mapa.
Isso é muito semelhante ao exemplo de contagem de palavras no hadoop. Trabalho de mapa: conte a frequência ou os tempos de todos os elementos exibidos. Reduzir: obtenha o elemento K superior.
Normalmente, eu daria ao recrutador duas respostas. Dê a eles o que quiserem. Obviamente, a codificação de redução de mapa seria trabalhosa, porque você precisa conhecer todos os parâmetros exatos. Nenhum dano para praticá-lo. Boa sorte.
fonte
Uma solução muito fácil seria percorrer a matriz 100 vezes. Qual é
O(n)
.Cada vez que você obtém o maior número (e altera seu valor para o valor mínimo, para que você não o veja na próxima iteração, ou acompanha os índices das respostas anteriores (mantendo o controle dos índices que a matriz original pode ter múltiplo do mesmo número)). Após 100 iterações, você tem os 100 maiores números.
fonte
Inspirado na resposta do @ron teller, aqui está um programa C de barebones para fazer o que você deseja.
Na minha máquina (core i3 com um SSD rápido), são necessários 25 segundos e 1724 classificações. Eu gerei um arquivo binário com
dd if=/dev/urandom/ count=1000000000 bs=1
para esta execução.Obviamente, há problemas de desempenho com a leitura de apenas 4 bytes por vez - do disco, mas isso é por exemplo. No lado positivo, é necessária muito pouca memória.
fonte
A solução mais simples é varrer a matriz grande de bilhões de números e manter os 100 maiores valores encontrados até agora em um buffer de matriz pequena sem nenhuma classificação e lembrar o menor valor desse buffer. Primeiro, achei que esse método foi proposto pelo fordprefect, mas em um comentário, ele disse que assumiu a estrutura de dados com 100 números sendo implementada como um heap. Sempre que for encontrado um novo número maior, o mínimo no buffer será substituído pelo novo valor encontrado e o buffer será procurado pelo mínimo atual novamente. Se os números em bilhões de matrizes numéricas forem distribuídos aleatoriamente na maioria das vezes, o valor da matriz grande será comparado ao mínimo da matriz pequena e descartado. Somente para uma fração muito pequena de número, o valor deve ser inserido na matriz pequena. Portanto, a diferença de manipular a estrutura de dados que contém os pequenos números pode ser negligenciada. Para um pequeno número de elementos, é difícil determinar se o uso de uma fila prioritária é realmente mais rápido do que usar minha abordagem ingênua.
Quero estimar o número de inserções no pequeno buffer de matriz de 100 elementos quando a matriz de 10 ^ 9 elementos é digitalizada. O programa varre os primeiros 1000 elementos dessa grande matriz e precisa inserir no máximo 1000 elementos no buffer. O buffer contém 100 elementos dos 1000 elementos verificados, ou seja, 0,1 do elemento verificado. Portanto, assumimos que a probabilidade de um valor da matriz grande ser maior que o mínimo atual do buffer é de cerca de 0,1. Esse elemento deve ser inserido no buffer. Agora o programa varre os próximos 10 ^ 4 elementos da matriz grande. Porque o mínimo do buffer aumentará toda vez que um novo elemento for inserido. Estimamos que a proporção de elementos maior que o mínimo atual seja de cerca de 0,1 e, portanto, haja 0,1 * 10 ^ 4 = 1000 elementos a serem inseridos. Na verdade, o número esperado de elementos que são inseridos no buffer será menor. Após a varredura desses 10 ^ 4 elementos, a fração dos números no buffer será de cerca de 0,01 dos elementos varridos até o momento. Portanto, ao digitalizar os próximos 10 ^ 5 números, assumimos que não mais de 0,01 * 10 ^ 5 = 1000 serão inseridos no buffer. Continuando essa argumentação, inserimos cerca de 7000 valores após a varredura de 1000 + 10 ^ 4 + 10 ^ 5 + ... + 10 ^ 9 ~ 10 ^ 9 elementos da matriz grande. Portanto, ao digitalizar uma matriz com 10 ^ 9 elementos de tamanho aleatório, esperamos não mais do que 10 ^ 4 (= 7000 arredondadas) inserções no buffer. Após cada inserção no buffer, o novo mínimo deve ser encontrado. Se o buffer é uma matriz simples, precisamos de 100 comparações para encontrar o novo mínimo. Se o buffer for outra estrutura de dados (como um heap), precisamos de pelo menos 1 comparação para encontrar o mínimo. Para comparar os elementos da grande matriz, precisamos de 10 ^ 9 comparações. Portanto, em geral, precisamos de comparações de 10 ^ 9 + 100 * 10 ^ 4 = 1,001 * 10 ^ 9 ao usar uma matriz como buffer e pelo menos 1.000 * 10 ^ 9 comparações ao usar outro tipo de estrutura de dados (como um heap) . Portanto, o uso de um heap gera apenas um ganho de 0,1% se o desempenho for determinado pelo número de comparação. Mas qual é a diferença no tempo de execução entre inserir um elemento em um heap de 100 elementos e substituir um elemento em uma matriz de 100 elementos e encontrar seu novo mínimo? 000 * 10 ^ 9 comparações ao usar outro tipo de estrutura de dados (como um heap). Portanto, o uso de um heap gera apenas um ganho de 0,1% se o desempenho for determinado pelo número de comparação. Mas qual é a diferença no tempo de execução entre inserir um elemento em um heap de 100 elementos e substituir um elemento em uma matriz de 100 elementos e encontrar seu novo mínimo? 000 * 10 ^ 9 comparações ao usar outro tipo de estrutura de dados (como um heap). Portanto, o uso de um heap gera apenas um ganho de 0,1% se o desempenho for determinado pelo número de comparação. Mas qual é a diferença no tempo de execução entre inserir um elemento em um heap de 100 elementos e substituir um elemento em uma matriz de 100 elementos e encontrar seu novo mínimo?
No nível teórico: quantas comparações são necessárias para inserir em uma pilha. Eu sei que é O (log (n)), mas quão grande é o fator constante? Eu
No nível da máquina: qual é o impacto do cache e da previsão de ramificação no tempo de execução de uma inserção de heap e uma pesquisa linear em uma matriz.
No nível da implementação: Quais custos adicionais estão ocultos em uma estrutura de dados de heap fornecida por uma biblioteca ou compilador?
Penso que estas são algumas das perguntas que precisam ser respondidas antes que se possa tentar estimar a diferença real entre o desempenho de um heap de 100 elementos ou de um array de 100 elementos. Portanto, faria sentido fazer um experimento e medir o desempenho real.
fonte
Algoritmo Maiores x elementos de n:
Vou chamar o valor de retorno LIST . É um conjunto de elementos x (na minha opinião, deve ser uma lista vinculada)
Então, qual é o pior cenário?
x log (x) + (nx) (log (x) +1) = nlog (x) + n - x
Então esse é o tempo O (n) para o pior caso. O +1 é a verificação se o número é maior que o menor na LIST. O tempo esperado para o caso médio dependerá da distribuição matemática desses n elementos.
Possíveis melhorias
Esse algoritmo pode ser ligeiramente aprimorado para o pior cenário, mas IMHO (não posso provar essa afirmação) que degradará o comportamento médio. O comportamento assintótico será o mesmo.
A melhoria neste algoritmo será que não verificaremos se o elemento é maior que o menor. Para cada elemento, tentaremos inseri-lo e, se for menor que o menor, desconsideramos. Embora isso pareça absurdo, se considerarmos apenas o pior cenário, teremos
x log (x) + (nx) log (x) = nlog (x)
operações.
Para este caso de uso, não vejo mais melhorias. No entanto, você deve se perguntar - e se eu tiver que fazer isso mais do que log (n) vezes e para diferentes x-es? Obviamente, classificamos essa matriz em O (n log (n)) e pegamos nosso elemento x sempre que precisamos deles.
fonte
Esta pergunta seria respondida com complexidade de N log (100) (em vez de N log N) com apenas uma linha de código C ++.
A resposta final seria um vetor em que os 100 primeiros elementos são garantidos como os 100 maiores números de sua matriz, enquanto os demais elementos são desordenados
O C ++ STL (biblioteca padrão) é bastante útil para esse tipo de problema.
Nota: Não estou dizendo que esta é a solução ideal, mas isso salvaria sua entrevista.
fonte
A solução simples seria usar uma fila prioritária, adicionar os primeiros 100 números à fila e acompanhar o menor número da fila, percorrer os outros bilhões de números e, sempre que encontrarmos um número maior que o maior número na fila de prioridade, removemos o menor número, adicionamos o novo número e, novamente, controlamos o menor número na fila.
Se os números estivessem em ordem aleatória, isso funcionaria muito bem porque, como iteramos através de um bilhão de números aleatórios, seria muito raro que o próximo número estivesse entre os 100 maiores até agora. Mas os números podem não ser aleatórios. Se a matriz já estivesse classificada em ordem crescente, sempre inseriríamos um elemento na fila de prioridade.
Então escolhemos, digamos, 100.000 números aleatórios da matriz primeiro. Para evitar o acesso aleatório que pode ser lento, adicionamos, digamos, 400 grupos aleatórios de 250 números consecutivos. Com essa seleção aleatória, podemos ter certeza de que pouquíssimos números restantes estão entre os cem primeiros; portanto, o tempo de execução será muito próximo ao de um loop simples que compara um bilhão de números a algum valor máximo.
fonte
É melhor encontrar os 100 melhores de um bilhão de números usando min-heap de 100 elementos.
Primeiro, prepare o min-heap com os 100 primeiros números encontrados. min-heap armazenará o menor dos 100 primeiros números na raiz (em cima).
Agora, à medida que avança o resto dos números, compare-os apenas com a raiz (o menor dos 100).
Se o novo número encontrado for maior que a raiz do min-heap, substitua a raiz por esse número, caso contrário, ignore-a.
Como parte da inserção do novo número no min-heap, o menor número no heap chegará ao topo (raiz).
Depois de passar por todos os números, teremos os 100 maiores números no min-heap.
fonte
Eu escrevi uma solução simples em Python, caso alguém esteja interessado. Ele usa o
bisect
módulo e uma lista de retorno temporária, que é mantida classificada. Isso é semelhante a uma implementação de fila prioritária.Uso com 100.000.000 de elementos e entrada na pior das hipóteses, que é uma lista classificada:
Demorou cerca de 40 segundos para calcular isso para 100.000.000 de elementos, então estou com medo de fazer isso por 1 bilhão. Para ser justo, porém, eu estava alimentando a entrada do pior caso (ironicamente, uma matriz que já está classificada).
fonte
Eu vejo muitas discussões de O (N), então proponho algo diferente apenas para o exercício de pensamento.
Existe alguma informação conhecida sobre a natureza desses números? Se for de natureza aleatória, não vá mais longe e veja as outras respostas. Você não obterá melhores resultados do que eles.
Contudo! Veja se qualquer mecanismo de preenchimento de lista preencheu essa lista em uma ordem específica. Eles estão em um padrão bem definido, onde você pode saber com certeza que a maior magnitude de números será encontrada em uma determinada região da lista ou em um determinado intervalo? Pode haver um padrão para isso. Se é assim, por exemplo, se eles garantem que estão em algum tipo de distribuição normal com a característica hump no meio, sempre apresentam tendências ascendentes repetidas entre subconjuntos definidos, têm um pico prolongado em algum momento T no meio dos dados definido como talvez uma incidência de abuso de informações privilegiadas ou falha de equipamento, ou talvez apenas tenha um "pico" a cada enésimo número, como na análise de forças após uma catástrofe, você pode reduzir o número de registros que precisa verificar significativamente.
De qualquer maneira, há algum pensamento para pensar. Talvez isso ajude você a dar uma resposta ponderada aos futuros entrevistadores. Sei que ficaria impressionado se alguém me fizesse essa pergunta em resposta a um problema como esse - isso me diria que eles estão pensando em otimização. Apenas reconheça que nem sempre existe a possibilidade de otimizar.
fonte
Crie uma lista vazia de 100 slots vazios
Para cada número na lista de entrada:
Se o número for menor que o primeiro, pule
Caso contrário, substitua-o por este número
Em seguida, empurre o número pelo swap adjacente; até que seja menor que o próximo
Retornar a lista
Nota: se o
log(input-list.size) + c < 100
, a melhor maneira é classificar a lista de entrada e, em seguida, divida os 100 primeiros itens.fonte
A complexidade é O (N)
Primeiro, crie uma matriz de 100 ints, inicialize o primeiro elemento dessa matriz como o primeiro elemento dos valores N, acompanhe o índice do elemento atual com outra variável, chame-o de CurrentBig
Repita os valores N
quando terminar, imprima a matriz M do CurrentBig 100 vezes o módulo 100 :-) Para o aluno: verifique se a última linha do código não supera os dados válidos logo antes do código sair
fonte
Outro algoritmo O (n) -
O algoritmo encontra os 100 maiores por eliminação
considere todos os milhões de números em sua representação binária. Comece do bit mais significativo. Encontrar se o MSB é 1 pode ser feito por uma multiplicação de operações booleanas com um número apropriado. Se houver mais de 100 1 nesse milhão, elimine os outros números com zeros. Agora, os números restantes prosseguem com o próximo bit mais significativo. mantenha uma contagem do número de números restantes após a eliminação e continue enquanto esse número for maior que 100.
A principal operação booleana pode ser realizada paralelamente nas GPUs
fonte
Eu descobriria quem tinha tempo para colocar um bilhão de números em uma matriz e o demitiria. Deve trabalhar para o governo. Pelo menos, se você tivesse uma lista vinculada, poderia inserir um número no meio sem mover meio bilhão para abrir espaço. Ainda melhor, um Btree permite uma pesquisa binária. Cada comparação elimina metade do seu total. Um algoritmo de hash permitiria preencher a estrutura de dados como um tabuleiro de damas, mas não tão bom para dados esparsos. Como sua melhor aposta é ter uma matriz de soluções com 100 números inteiros e acompanhar o número mais baixo na matriz de soluções, para que você possa substituí-lo quando encontrar um número maior na matriz original. Você precisaria examinar todos os elementos da matriz original, desde que não estejam ordenados para começar.
fonte
Você pode fazer isso a
O(n)
tempo. Basta percorrer a lista e acompanhar os 100 maiores números que você já viu em um determinado momento e o valor mínimo nesse grupo. Quando você encontrar um novo número maior, o menor dos seus dez, substitua-o e atualize seu novo valor mínimo de 100 (pode levar um tempo constante de 100 para determinar isso cada vez que você o faz, mas isso não afeta a análise geral )fonte
Gerenciar uma lista separada é um trabalho extra e você precisa mover as coisas pela lista toda vez que encontrar outra substituição. Basta classificá-lo e pegar o top 100.
fonte
Por favor, note esp. o segundo passo pode ser fácil de calcular em paralelo! E também será eficiente quando você precisar de um milhão de elementos maiores.
fonte
É uma pergunta do Google ou de outros gigantes da indústria. Talvez o código a seguir seja a resposta certa esperada pelo seu entrevistador. O custo de tempo e de espaço depende do número máximo na matriz de entrada.
fonte
eu fiz meu próprio código, não tenho certeza se é o que o "entrevistador" está procurando
fonte
Possíveis melhorias.
Se o arquivo contiver 1 bilhão de números, a leitura poderá ser muito longa ...
Para melhorar esse trabalho, você pode:
fonte
Primeiro, pegue 1000 elementos e adicione-os em um heap máximo. Agora retire os primeiros 100 elementos no máximo e guarde-os em algum lugar. Agora escolha os próximos 900 elementos do arquivo e adicione-os ao heap junto com os últimos 100 elementos mais altos.
Continue repetindo esse processo de pegar 100 elementos da pilha e adicionar 900 elementos do arquivo.
A escolha final de 100 elementos nos dará o máximo de 100 elementos de um bilhão de números.
fonte
Problema: Encontre m maiores elementos de n itens em que n >>> m
A solução mais simples, que deve ser óbvia para todos, é simplesmente fazer m passes do algoritmo de classificação por bolhas.
depois imprima os últimos n elementos da matriz.
Isso não requer estruturas de dados externas e usa um algoritmo que todos conhecem.
A estimativa do tempo de execução é O (m * n). As melhores respostas até agora são O (n log (m)), portanto, esta solução não é significativamente mais cara para m pequenos.
Não estou dizendo que isso não poderia ser melhorado, mas essa é de longe a solução mais simples.
fonte