Écrire un programme pour trouver les 100 plus grands nombres d'un tableau de 1 milliards de chiffres
J'ai récemment assisté à une interview où on m'a demandé "écrire un programme pour trouver les 100 plus grands nombres d'un tableau de 1 milliard de dollars de chiffres".
J'ai seulement été en mesure de donner une force brute solution qui a été pour trier le tableau en O(nlogn) le temps de la complexité et de prendre les 100 derniers numéros.
Arrays.sort(array);
L'intervieweur a la recherche d'un meilleur temps de la complexité, j'ai essayé un couple de d'autres solutions, mais a échoué à lui répondre. Est-il un meilleur temps de la complexité de la solution?
- Bucketsort pourrait être une allusion
- Peut-être le problème, c'est que ce n'était pas une question de tri, mais un à la recherche d'un.
- Comme une note technique de tri peut être pas le meilleur moyen de résoudre le problème, mais je ne pense pas que c'est de la force brute - je pense à une aggravation de la situation, des moyens de le faire.
- Une autre force brute méthode serait de créer un réseau parallèle dans lequel vous stocker la position de chaque chiffre dans le "plus grand nombre" de la concurrence. Vous itérer le premier élément et affecter un 1. Lorsque vous arrivez à la 8701th un vous parcourez la précédente 8700 et "mise à jour" de leur position: Ajouter 1 s'ils sont inférieurs, et de la laisser dans le cas contraire (mais dans ce cas, ajouter un à la position de l'actuel, 8701th, nombre). Il est probablement en O(n^2).
- Voir en.wikipedia.org/wiki/Partial_sorting et en.wikipedia.org/wiki/Selection_algorithm
- Je viens de penser à un encore plus stupide de la force brute de la méthode...de Trouver toutes les combinaisons possibles de 100 éléments de la 1 milliards d'élément de tableau et de voir laquelle de ces combinaisons a la somme la plus importante.
- Vous pouvez également parcourir le tableau et la copie de ses effectifs en une carte de jeux, dans lequel la clé est le nombre de chiffres de chaque numéro d'origine est. Alors vous ne devez effectuer une itération de votre carte par la clé dans le sens inverse de l'ordre et de garder saisissant vos numéros et de les compter. À un certain moment vous aimerai atteindre au-delà de 100 numéros, de sorte que vous besoin de sélectionner seulement certains des chiffres de la dernière série; dire par exemple que les jeux avec plus de 9 chiffres vous avais donné 96 numéros, et un ensemble de nombres à 8 chiffres contient 9 numéros: vous avez seulement besoin de 4 d'entre eux de sorte que vous aurez besoin de les trouver... par la force brute, bien sûr 🙂
- Cette dernière stratégie a ses binaire de contrepartie, ce qui est intéressant, car il pourrait être appliqué sans l'aide de l'espace supplémentaire. Lire le premier bit de chaque numéro, en fonction du type dans lequel elle est stockée. Si il y a plus de 100
1
, garder tous ces chiffres et d'éliminer ceux avec0
; sinon, vous avez déjà des gagnants (dire, 63) et vous avez besoin de garder une itération de trouver le reste des 37 numéros. Vous ferez cela en regardant le deuxième bit. Vous allez balayer les nombres de gauche à droite, de sorte que vous pouvez directement choisir ceux avec la plus extrême gauche1
s'. - Notez que tous les déterministe (et corriger) les algorithmes sont
O(1)
dans ce cas, car il n'y a pas de dimension augmentation. L'enquêteur doit m'ont demandé "Comment trouver les m plus grands éléments à partir d'un tableau de n avec n >> m?". - Oui, nous avons été en supposant que n a été l'un milliard seulement par le contexte. La confusion des concepts que l'interviewer a eu, c'est plutôt commun, à partir de mon expérience.
- Je suis peut-être fou, mais ne pourriez-vous pas utiliser une variation sur un radix MSD trier pour en faire un algorithme O(n)?
- Voir aussi: Obtenir les 100 plus grand nombre à partir d'une liste infinie
- Wow, comment cette question peut devenir 59 jusqu'voix et la meilleure réponse 58 upvotes alors que cette question est seulement de 16 heures?
- Il n'est pas rare que certaines question a plus de 50 upvotes après un jour. Ils sont une minorité, mais bien souvent, vous pouvez trouver l'un d'eux.
- Cette question montre l'effort de la recherche; je pense que je vais upvote il. 79 d'autres peut-être pas tort, après tout.
- Également similaire à Comment puis-je trier 1 millions de numéros, et d'imprimer uniquement le top 10 en Python?
- Il a également été en vedette dans le stackoverflow newsletter. Que j'ai pour elle, et c'est comment il a obtenu ma upvote.
- J'ai trouvé que l'utilisation d'un tri rapide est très efficace avec un grand nombre de tableaux
- Je pense juste parcourant chaque nombre dans la grande liste et supprimer des numéros de haut en devient finalement plus efficace que le tri si
m
reste constante etn
augmente... - statistiques.
- Cela semble être un problème de statistiques d'ordre... trouver le 100e plus petit numéro de dire N dans la liste et ensuite il suffit de parcourir le tableau une fois pour sélectionner tous les numéros moindre que le N. Pour plus de vérifier Erik de conférence 6 (MIT analyse d'algorithmes ) .
- Je pense que nous pouvons tout simplement obtenir en O(n) . Nous pouvons utiliser de tri à bulles pour obtenir les 100 plus grands éléments en utilisant le code suivant
- Double Possible de Récupération du top 100 des numéros à partir d'une centaine de millions de chiffres
Vous devez vous connecter pour publier un commentaire.
Vous pouvez garder une file d'attente prioritaire de les 100 plus grand nombre, l'itération à travers les milliards de chiffres, chaque fois que vous rencontrez un nombre plus grand que le plus petit numéro dans la file d'attente (la tête de la file d'attente), de supprimer la tête de la file d'attente et ajouter le nouveau numéro de la file d'attente.
EDIT:
en tant que Dev a noté, avec une file d'attente de priorité mis en œuvre par un segment de mémoire, la complexité de l'insertion pour la file d'attente est
O(logN)
Dans le pire des cas, vous obtenez
billionlog2(100)
ce qui est mieux quebillion
log2(billion)
En général, si vous avez besoin le plus grand K nombres à partir d'un ensemble de N nombres, la complexité est
O(NlogK)
plutôt queO(NlogN)
, cela peut être très important lorsque K est très faible en comparaison des N.EDIT2:
Le temps de cet algorithme est assez intéressant, car à chaque itération une insertion peut ou peut ne pas se produire. La probabilité de la i-ième nombre pour être inséré dans la file d'attente est la probabilité d'une variable aléatoire est supérieure à au moins
i-K
variables aléatoires à partir de la même distribution (les k premiers nombres sont automatiquement ajoutés à la file d'attente). Nous pouvons utiliser les statistiques d'ordre (voir lien) pour calculer cette probabilité. Par exemple, supposons les nombres ont été choisis au hasard uniformément de{0, 1}
, la valeur attendue de (i-K), le nombre (de je numéros) est(i-k)/i
, et la probabilité d'une variable aléatoire étant plus grande que cette valeur est1-[(i-k)/i] = k/i
.Ainsi, le nombre d'insertions est:
Et de la durée d'exécution peut être exprimé comme:
(
k
temps de génération de la file d'attente avec le premierk
éléments, puisn-k
comparaisons, et le nombre d'insertions, comme décrit ci-dessus, chacun prend une moyennelog(k)/2
temps)Noter que lorsque
N
est très grand en comparaison desK
, cette expression est beaucoup plus proche den
plutôt queNlogK
. C'est un peu intuitif, comme dans le cas de la question, même après 10000 itérations (ce qui est très faible comparer à un milliard de dollars), les chances d'un certain nombre pour être inséré dans la file d'attente est très faible.k
constant et petits par rapport àn
. Cependant, on devrait toujours garder à l'esprit cette "situation normale".O(100)=O(constant)=O(1)
. Il n'est pas question que le constat que vous utilisez, donc je ne reçois pas ce qu'est le "non-sens" à propos deO(100)
.k/i
oùi=k+1...n
, tout comme dans le calcul, et que est précis.sum_{i=k+1}^n 1/i = ln(n)-ln(k)+O(1)
par Euler–Mascheroni.Si cela est demandé dans une interview, je pense que l'intervieweur veut probablement voir votre processus de résolution de problème, et pas seulement vos connaissances des algorithmes.
La description est tout à fait général, donc peut-être que vous pouvez lui demander de la plage ou de la signification de ces chiffres pour rendre le problème clairement. Cela peut impressionner l'intervieweur. Si, par exemple, ces numéros de stands pour les gens de l'âge de l'intérieur d'un pays (par ex. la Chine),alors il est beaucoup plus facile de problème. Avec une hypothèse raisonnable que la personne en vie est de plus de 200, vous pouvez utiliser un tableau int de taille 200(peut-être 201) pour compter le nombre de personnes ayant le même âge en une seule itération. Ici, l'indice moyen de l'âge. Après cela, il est un morceau de gâteau pour trouver les 100 plus grand nombre. Par la façon dont cette algo est appelé comptage tri.
De toute façon, faire de la question plus spécifique et la plus claire qui est bon pour vous, dans une interview.
Vous pouvez effectuer une itération sur les numéros qui prend O(n)
Chaque fois que vous trouvez une valeur plus grande que le minimum actuel, ajouter la nouvelle valeur à une circulaire de la file d'attente à la taille 100.
Le min de file d'attente circulaire est votre nouvelle valeur de comparaison. Maintenir sur l'ajout de la file d'attente. Si complet, extraire le minimum de la file d'attente.
J'ai réalisé que c'est taggés avec "algorithme", mais va jeter quelques autres options, car il devrait également être étiqueté "entretien".
Quelle est la source de la 1 milliards de chiffres? Si c'est une base de données, puis "select valeur from table order by desc limit 100' faire le travail très bien, - il pourrait y avoir des différences dialectales.
Est-ce un one-off, ou quelque chose qui va être répété? En cas de récidive, à quelle fréquence? Si c'est un one-off et les données sont dans un fichier, puis "chat srcfile | tri (les options nécessaires) | tête -100' vous permettra de vous faire rapidement un travail productif que vous êtes payé pour le faire alors que l'ordinateur gère cette petite corvée.
Si elle est répétée, vous conseille cueillette toute bonne approche pour obtenir la réponse initiale et store /cache les résultats de sorte que vous pourriez être en permanence en mesure de faire rapport dans le top 100.
Enfin, il y a cette considération. Vous êtes à la recherche d'un emploi de niveau d'entrée et une entrevue avec un geek manager ou futur co-travailleur? Si oui, alors vous pouvez jeter toutes sortes d'approches décrivant la technique relative des avantages et des inconvénients. Si vous êtes à la recherche pour plus de gestion de l'emploi, puis l'aborder comme un gestionnaire, concernés par le développement et les coûts de maintenance de la solution, et de dire "merci beaucoup" et de laisser si c'est l'interviewer veut se concentrer sur CS de trivia. Il et vous serait probablement pas beaucoup d'avancement du potentiel.
Meilleure chance la prochaine entrevue.
Ma réaction immédiate pour ce qui serait d'utiliser un segment, mais il y a moyen d'utiliser QuickSelect sans garder toutes les valeurs d'entrée à portée de main à tout moment.
Créer un tableau de taille 200 et de le remplir avec les 200 premières valeurs d'entrée. Exécuter QuickSelect et jetez le bas 100, vous laissant avec 100 places de parking libres. Lire dans les 100 prochaines valeurs d'entrée et exécuter QuickSelect de nouveau. Continuer jusqu'à ce que vous avez exécuté si l'ensemble de l'entrée en lots de 100.
À la fin vous avez le top 100 des valeurs. Pour N valeurs que vous avez exécuté QuickSelect à peu près N/100 fois. Chaque Quickselect coût d'environ 200 fois une constante, de sorte que le coût total est 2N fois une constante. Cela ressemble linéaire en la taille de l'entrée, pour moi, quelle que soit la taille de paramètre que je suis brancher à 100 dans cette explication.
partial_sort
exécuter directement sur un ensemble de données de 200 millions de 32 bitsint
(créé par un MT19937, uniformément distribués).Ordering.greatestOf(Iterable, int)
ne. Il est absolument linéaire en temps et en un seul passage et il est super mignon algorithme. FWIW, nous avons aussi quelques points de repère: ses facteurs constants sont un poil plus lent que la traditionnelle file d'attente de priorité dans la moyenne des cas, mais cette mise en œuvre est beaucoup plus résistant à la le "pire des cas" d'entrée (par exemple, strictement croissant d'entrée).Vous pouvez utiliser Sélection rapide de l'algorithme pour trouver le numéro(par ordre) index [milliards de dollars-101]
et puis itérer sur les nombres et pour trouver les numéros qui biger à partir de ce numéro.
Cet algorithme est la suivante: 2 X O(N) = O(N) (Moyenne des performances)
La deuxième option comme Thomas Jungblut suggérer:
Utilisation Tas la construction de la MAXI tas prendre en O(N),puis le top 100 max numéros seront en haut de l'échelle, tous vous avez besoin est de les mettre dans le tas(100 X O(Log(N)).
Cet algorithme est la suivante:O(N) + 100 X O(Log(N)) = O(N)
O(N)
, faisant deux QuickSelects et une autre analyse linéaire est beaucoup plus de ressources que nécessaire.100*O(N)
(si c'est une syntaxe valide) =O(100*N)
=O(N)
(certes 100 peut être variable, si oui, ce n'est pas strictement vrai). Oh, et Quickselect a pire des cas, la performance de O(N^2) (ouch). Et si elle ne rentre pas dans la mémoire, vous serez en rechargeant les données à partir du disque deux fois, ce qui est bien pire qu'une fois (ce qui est le goulot d'étranglement).Bien que les autres quickselect solution a été downvoted, le fait demeure que quickselect trouverez la solution plus rapide que l'utilisation d'une file d'attente de taille 100. Quickselect a prévu un temps de course de 2n + o(n), en termes de comparaisons. Très simplement la mise en œuvre serait
Cela va prendre 3n + o(n) comparaisons en moyenne. En outre, il peut être plus efficace en utilisant le fait que quickselect va laisser la plus grande de 100 articles dans la matrice de dans la de 100 la droite-la plupart des endroits. Donc, en fait, le temps de fonctionnement peut être amélioré à 2n+o(n).
Il y a le problème que cela est prévu, la durée, et pas le pire des cas, mais en utilisant un décent de pivot de la stratégie de sélection (par exemple, choisir de 21 éléments au hasard, et choisir la médiane de ces 21 comme pivot), puis le nombre de comparaisons peuvent être garanties avec une forte probabilité d'être au plus (2+c)n pour un arbitrairement petite constante c.
En effet, en utilisant un échantillonnage optimisé stratégie (par exemple, l'échantillon sqrt(n) éléments au hasard, et choisir le 99e percentile), le temps d'exécution peut être obtenu vers le bas (1+c)n + o(n) pour arbitrairement petite c (en supposant que K, le nombre d'éléments à sélectionner o(n)).
Sur l'autre main, à l'aide d'une file d'attente de taille 100 exigera O(log(100)n) comparaisons, et le logarithme de base 2 de 100 est approximativement égale à 6,6.
Si nous pensons à ce problème dans les plus abstraits sens de choisir le plus grand K éléments d'un tableau de taille N, où K=o(N) mais les deux K et N va à l'infini, alors le temps d'exécution de la quickselect version sera en O(N) et la file d'attente de la version O(N log K), donc dans ce sens quickselect est aussi asymptotiquement supérieur.
Dans les commentaires, il a été mentionné que la file d'attente de solution sera exécuté dans le délai prévu N + K log N aléatoires d'entrée. Bien sûr, le hasard d'entrée hypothèse n'est jamais valide, à moins que la question des états explicitement. La file d'attente de solution pourrait être fait pour parcourir le tableau dans un ordre aléatoire, mais cela devra assumer le coût supplémentaire de N appels à un générateur de nombre aléatoire comme permutant l'ensemble de l'entrée de tableau ou d'autre allouer un nouveau tableau de longueur N contenant au hasard des indices.
Si le problème n'est pas de vous permettre de déplacer les éléments dans le tableau d'origine, et le coût de l'allocation de mémoire est élevée, afin de dupliquer le tableau n'est pas une option, c'est une question différente. Mais strictement en termes de temps d'exécution, c'est la meilleure solution.
prendre les 100 premiers numéros de l'milliards de dollars et les trier. maintenant, juste itérer à travers des milliards de dollars, si le nombre est supérieur au plus petit des 100, insérer dans l'ordre de tri. Ce que vous vous retrouvez avec quelque chose de beaucoup plus proche de O(n) sur la taille de l'ensemble.
Deux options:
(1) Tas (priorityQueue)
Maintenir un min-tas avec une taille de 100. Parcourir le tableau. Une fois que l'élément est plus petit que le premier élément dans le tas, il faut le remplacer.
(2) Carte-réduction de modèle.
Ceci est très similaire à word count exemple dans hadoop.
La carte de l'emploi: compter chaque élément de la fréquence ou de temps est apparu.
Réduire: Obtenir le meilleur K de l'élément.
Habituellement, je donnerais le recruteur deux réponses. Leur donner ce qu'ils veulent. Bien sûr, la carte de réduire le codage serait de main-certains parce que vous devez connaître tous les paramètres exacts. Pas de mal à le pratiquer.
Bonne Chance.
Une solution très simple serait de parcourir le tableau de 100 fois. Qui est
O(n)
.Chaque fois que vous tirez le plus grand nombre (et le changement de sa valeur à la valeur minimale, de sorte que vous ne le voyez pas dans la prochaine itération, ou de garder la trace des indices de réponse à la question précédente (en gardant la trace des indices du tableau original peut avoir plusieurs fois le même nombre)). Après 100 itérations, vous avez les 100 plus grands nombres.
Inspiré par @ron de guichets de la réponse, voici un barebones programme C de faire ce que vous voulez.
Sur ma machine (core i3 avec une rapide SSD), il prend 25 secondes, et 1724 sortes.
J'ai généré un fichier binaire avec
dd if=/dev/urandom/count=1000000000 bs=1
pour cette course.Évidemment, il y a des problèmes de performances avec la lecture de seulement 4 octets à la fois - à partir du disque, mais c'est pour l'exemple du saké. Sur le côté positif, très peu de mémoire est nécessaire.
La solution la plus simple consiste à analyser les milliards de chiffres grand tableau et maintenez-les 100 plus grandes valeurs trouvées jusqu'à présent dans un petit tableau tampon sans aucun tri et n'oubliez pas la plus petite valeur de ce tampon. J'ai d'abord pensé que cette méthode a été proposée par fordprefect mais dans un commentaire, il dit qu'il a assumé les 100 nombre de structure de données à la mise en œuvre d'un tas. Chaque fois qu'un nouveau numéro est trouvé qui est plus grand que le minimum dans la mémoire tampon est remplacée par la nouvelle valeur trouvée et la mémoire tampon est recherché pour le minimum actuel de nouveau. Si les chiffres en milliards de dollars numéro de tableau sont distribués de façon aléatoire, la plupart du temps la valeur à partir de la vaste gamme est comparée à la valeur minimale de la petite matrice et jetés. Pour une très petite fraction de nombre, la valeur doit être inséré dans le petit tableau. Donc la différence de la manipulation de la structure de données en tenant le petit nombre peut être négligée. Pour un petit nombre d'éléments qu'il est difficile de déterminer si l'utilisation d'une file d'attente de priorité est effectivement plus rapide que d'utiliser mon approche naïve.
Je veux estimer le nombre de plaquettes dans le petit 100 élément de la matrice de mémoire tampon lorsque le 10^9 élément de tableau est analysé. Le programme analyse les 1000 premiers éléments de ce grand tableau et a insérer au plus de 1000 éléments dans la mémoire tampon. La mémoire tampon contient 100 élément de 1000 éléments numérisés, c'est-à 0.1 de l'élément analysé. Donc, nous supposons que la probabilité pour qu'une valeur dans le grand tableau est plus grand que le minimum actuel de la mémoire tampon est d'environ 0,1 Tel élément doit être inséré dans la mémoire tampon . Maintenant, le programme scanne le prochain 10^4 éléments à partir de la vaste gamme. Parce que la valeur minimale de la mémoire tampon augmente chaque fois qu'un nouvel élément est inséré. Nous avons estimé que le ratio d'éléments plus grande que le minimum actuel est d'environ 0,1 et donc il y a 0.1*10^4=1000 éléments à insérer. En fait le nombre d'éléments qui sont insérés dans le tampon sera plus petite. Après l'analyse de ce 10^4 éléments fraction des nombres dans la mémoire tampon sera d'environ 0,01 des éléments analysés jusqu'à présent. Donc, lors de la numérisation de la prochaine 10^5 numéros, nous supposons que pas plus de 0,01*10^5=1000 sera inséré dans la mémoire tampon. La poursuite de cette argumentation, nous avons inséré environ 7000 valeurs après la numérisation 1000+10^4+10^5+...+10^9 ~ 10^9 les éléments de la grand tableau.
Donc, lors de la numérisation d'un tableau avec 10^9 éléments de taille aléatoire nous nous attendons à ce que pas plus de 10^4 (=7000 arrondi à la hausse) des insertions dans la mémoire tampon. Après chaque insertion dans la mémoire tampon du nouveau minimum doit être trouvé. Si le tampon est un simple tableau que nous avons besoin de 100 comparaison pour trouver le nouveau minimum. Si le tampon est une autre structure de données (comme un segment de mémoire), nous avons besoin d'au moins 1 comparaison pour trouver le minimum. Pour comparer les éléments de la grand tableau que nous avons besoin de 10^9 comparaisons. Donc dans l'ensemble nous avons besoin d'environ 10^9+100*10^4=1.001 * 10^9 comparaisons lors de l'utilisation d'un tableau en mémoire tampon et d'au moins 1.000 * 10^9 comparaisons lors de l'utilisation d'un autre type de structure de données (comme un segment de mémoire). Donc, en utilisant un tas apporte qu'un gain de 0,1% si le rendement est déterminé par le nombre de comparaison.
Mais qu'est-ce que la différence de temps d'exécution entre l'insertion d'un élément dans un 100 élément de segment et le remplacement d'un élément dans un 100 élément de tableau et de trouver son nouveau minimum?
Au niveau théorique: Comment faire de nombreuses comparaisons sont nécessaires pour l'insertion dans un tas. Je sais que c'est O(log(n)), mais de quelle taille est le facteur constant? Je
Au niveau de la machine: Quel est l'impact de la mise en cache et de la direction de la prévision sur le temps d'exécution d'un tas d'insertion et une recherche linéaire dans un tableau.
Au niveau de mise en œuvre: Quels sont les coûts supplémentaires sont cachés dans un tas de structure de données fournies par une bibliothèque ou un compilateur?
Je pense que ce sont certaines des questions qui doivent être répondues avant on peut essayer d'estimer la véritable différence entre les performances d'un 100 élément de segment ou un 100 élément de tableau. Il serait donc judicieux de réaliser une expérience, et de mesurer la performance réelle.
Algorithme Plus x des éléments de n:
J'appelle la valeur de retour LISTE. C'est un ensemble de x éléments (à mon avis, que devrait être liée liste)
Alors, quel est le pire scénario?
x log(x) + (n-x)(log(x)+1) = nlog(x) + n - x
C'est donc O(n) fois pour le pire des cas. Le +1 est de vérifier si le nombre est plus grand que le plus petit dans la LISTE. Le temps prévu pour la moyenne des cas dépendra de mathématique de la distribution de ces n éléments.
Améliorations possibles
Cet algorithme peut être légèrement améliorée pour les pires scénarios, mais à mon humble avis (je ne peux pas prouver cette affirmation) que va se dégrader comportement moyen. Comportement asymptotique sera le même.
Amélioration de cet algorithme que nous n'allons pas vérifier si un élément est plus grand que le plus petit. Pour chaque élément, nous allons essayer de l'insérer et si elle est plus petite que la plus petite que nous allons en faire abstraction. Bien que cela semble absurde si l'on considère seulement le pire des cas on aura
x log(x) + (n-x)log(x) = nlog(x)
opérations.
Pour ce cas d'utilisation je ne vois pas d'autres améliorations. Pourtant, vous devez vous demander que faire si j'ai à le faire plus que log(n) fois et pour différents x-es? Évidemment, nous permettrait de trier ce tableau en O(n log(n)) et prendre notre x de l'élément chaque fois que nous en avons besoin.
Cette question pourrait être répondu avec N log(100) de la complexité (au lieu de N log N) avec juste une ligne de code C++.
La réponse finale serait un vecteur où les 100 premiers éléments sont assurés d'être les 100 plus grand nombre d'entre vous de tableau, tandis que les autres éléments sont non ordonnée
C++ STL (standard library) est très pratique pour ce genre de problèmes.
Note: je ne dis pas que c'est la solution optimale, mais il aurait sauvé votre entrevue.
La solution la plus simple serait d'utiliser une file d'attente de priorité, en ajoutant les 100 premiers numéros de la file d'attente et de maintenir le plus petit numéro dans la file d'attente, puis une itération à travers les milliards d'autres numéros, et à chaque fois que nous en trouver un qui est plus grand que le plus grand nombre dans la file d'attente de priorité, nous avons supprimer le plus petit nombre, ajouter le nouveau numéro, et encore conserver la trace du plus petit numéro dans la file d'attente.
Si les numéros ont été dans un ordre aléatoire, ce beau parce que nous parcourir un milliard de nombres aléatoires, il est très rare que le prochain numéro est parmi les 100 plus importantes à ce jour. Mais le nombre ne peut pas être le hasard. Si le tableau est déjà trié dans l'ordre croissant puis nous toujours insérer un élément à la file d'attente de priorité.
Nous choisissons donc dire 100 000 aléatoire numéros à partir du tableau en premier. Pour éviter d'accès aléatoire qui peut être lente, nous ajoutons dire 400 groupes aléatoires de 250 numéros consécutifs. Avec que la sélection aléatoire, nous pouvons être tout à fait sûr que très peu de numéros restants sont dans le top cent, de sorte que le temps d'exécution sera très proche de celui d'une simple boucle de comparaison d'un milliard de dollars certaine valeur maximale.
Trouver le top 100 de un milliard de chiffres est mieux de le faire à l'aide de min-tas de 100 éléments.
Premier min-tas avec les 100 premiers nombres rencontrés. min-tas magasin le plus petit des 100 premiers numéros à la racine (en haut).
Maintenant, comme vous allez le long, le reste des numéros seulement de les comparer avec la racine (la plus petite de l'100).
Si le nouveau numéro de produit est plus grand que la racine de min-tas de remplacer la racine avec ce numéro contraire l'ignorer.
Dans le cadre de l'insertion d'un nouveau numéro en min-tas le plus petit nombre dans le tas viendra à la racine).
Une fois que nous avons traversé tous les chiffres qui nous aura le plus grand nombre à 100 numéros dans le min-tas.
J'ai rédigé une solution simple en Python dans le cas où quelqu'un est intéressé. Il utilise le
bisect
module et un retour temporaire de la liste qu'il garde triés. Ceci est similaire à une file d'attente de priorité de mise en œuvre.Utilisation avec 100 000 000 d'éléments et les pires cas, l'entrée qui est une liste triée:
Il a fallu environ 40 secondes pour calculer ce pour 100 000 000 d'éléments, donc je suis peur de le faire pour 1 milliard de dollars. Pour être juste bien, j'ai été nourrir le pire des cas, l'entrée (ironiquement, un tableau est déjà trié).
Je vois beaucoup de O(N) les discussions, j'ai donc proposer quelque chose de différent juste pour la pensée de l'exercice.
Est-il connu de l'information sur la nature de ces chiffres? Si c'est de l'aléatoire dans la nature, puis aller plus loin et de regarder les autres réponses. Vous n'aurez pas de meilleurs résultats qu'eux.
Cependant! Voir si quelle que soit la liste de remplir mécanisme peuplée que la liste dans un ordre particulier. Sont-ils dans un plan bien défini où vous pouvez savoir avec certitude que le plus grand de l'ampleur de numéros se trouvent dans une certaine région de la liste ou sur un certain intervalle? Il peut y avoir un motif pour cela. Si c'est le cas, par exemple, s'ils sont assurés d'être dans une sorte de distribution normale avec la caractéristique bosse dans le milieu, ont toujours répéter les tendances à la hausse parmi défini des sous-ensembles, ont une longue pic à un moment T dans le milieu du jeu de données, comme peut-être un cas de délit d'initié ou d'une défaillance de l'équipement, ou peut-être juste une "pointe" de chaque Nième nombre que dans l'analyse des forces après une catastrophe, vous pouvez réduire le nombre d'enregistrements que vous avez à vérifier de manière significative.
Il y a un peu de nourriture pour la pensée, de toute façon. Peut-être que ce sera vous aider à donner aux futurs enquêteurs une réponse réfléchie. Je sais que je serais impressionné si quelqu'un m'a posé cette question en réponse à un problème, ce serait me dire qu'ils sont de la pensée de l'optimisation. Il suffit de reconnaître qu'il peut ne pas toujours être possible d'optimiser.
Créer une liste vide de 100 logement vide
Pour chaque nombre dans la liste:
Si le nombre est plus petit que le premier, passez
Sinon le remplacer avec ce numéro
Ensuite, poussez le nombre adjacentes swap; jusqu'à ce qu'il est plus petit que le prochain
Retour la liste
Remarque: si le
log(input-list.size) + c < 100
, alors la meilleure façon est de trier les entrées-liste, puis divisés en premier 100 articles.La complexité est O(N)
D'abord créer un tableau de 100 entiers initialiaze le premier élément de ce tableau que le premier élément de la N des valeurs,
garder la trace de l'indice de l'élément en cours avec une autre variable, l'appeler CurrentBig
Itérer si les N valeurs
une fois cela fait , la M matrice de CurrentBig 100 fois modulo 100 🙂
Pour l'étudiant: assurez-vous que la dernière ligne de code n'a pas d'atout valide les données juste avant le code quitte
Un autre algorithme O(n) -
L'algorithme recherche les 100 plus par élimination
pensez à tous les millions de numéros dans leur représentation binaire. Commencer à partir de l'octet le plus significatif. Si le bit de poids fort est à 1 peut être fait par une opération booléenne de multiplication avec un nombre approprié. Si il y a plus de 100 1 dans ces millions d'éliminer les autres chiffres avec des zéros. Maintenant le reste des numéros de procéder à la prochaine most significant bit. tenir le compte du nombre de numéros restants après l'élimination et continuer tant que ce nombre est plus grand que 100.
La principale opération booléenne peut être un rapprochement effectué sur les Gpu
Je voudrais savoir qui a eu le temps de mettre un milliard de chiffres dans un tableau et de le congédier. Doit travailler pour le gouvernement. Au moins si vous aviez une liste, vous pouvez insérer un nombre dans le milieu, sans bouger d'un demi-milliard de dollars pour faire de la place. Encore mieux, un Arbre permet une recherche binaire. Chaque comparaison élimine la moitié de votre total. Un algorithme de hachage devrait vous permettre de remplir la structure de données comme un damier, mais pas très bon pour le peu de données. Comme il est de votre meilleur pari est d'avoir une solution de tableau de 100 entiers, et de suivre le nombre le plus faible de votre solution de tableau de sorte que vous pouvez le remplacer quand vous venez à travers un plus grand nombre dans le tableau d'origine. Vous devez examiner chaque élément dans le tableau d'origine, en supposant qu'il n'est pas triée pour commencer.
Vous pouvez le faire dans
O(n)
temps. Juste parcourir la liste et de garder trace des 100 plus grand nombre vous avez vu à un moment donné et la valeur minimale de ce groupe. Lorsque vous trouvez un nouveau numéro plus grand que le plus petit de vos dix, puis le remplacer et mettre à jour votre nouvelle valeur min de l'100 (cela peut prendre un temps constant de 100 à déterminer ce à chaque fois que vous faites, mais cela n'affecte pas l'analyse globale).La gestion d'une liste distincte est du travail supplémentaire et vous devez déplacer des choses autour de l'ensemble de la liste à chaque fois que vous trouver un autre remplacement. Juste qsort et de prendre le top 100.
Veuillez noter esp. la deuxième étape pourrait être facile à calculer en parallèle! Et il sera également efficace lorsque vous avez besoin d'un million de plus grands éléments.
C'est une question de Google ou quelque chose géants de l'industrie.Peut-être que le code suivant est le droit de réponse prévu par votre interlocuteur.
Le coût du temps et de l'espace des coûts dépendent du nombre maximum dans le tableau d'entrée.Pour 32-Bit int tableau d'entrée, L'espace maximal coût est de 4 * 125 millions d'Octets, le Temps coût est de 5 * Milliards de dollars.
j'ai fait mon propre code,vous ne savez pas si sa ce que "l'enquêteur" il est à la recherche
Améliorations possibles.
Si le fichier contient 1 milliards le nombre, la lecture pourrait être vraiment longtemps...
À améliorer ce travail, vous pouvez :
Prendre d'abord les éléments de 1000 et ajoutez-les dans un tas max. Maintenant, prenez le premier maxi de 100 éléments et de les stocker quelque part. Choisissez maintenant à côté de 900 éléments du dossier et les ajouter dans le tas avec la dernière 100 plus élevé de l'élément.
Continuez à répéter ce processus de la cueillette jusqu'à 100 éléments dans le tas et l'ajout de 900 éléments du dossier.
Le choix final de 100 éléments vont nous donner le maximum de 100 éléments d'un milliard de dollars de chiffres.
Ce code est pour trouver N plus grand nombre dans un non Triés tableau.
Cela pourrait ne pas être le plus efficace, mais fait le travail.
Espère que cette aide
std::nth_element(array, array+Array_Size, array+BILLION, std::greater<int>{});
fait le travail (de la part de l'élémentarray[Array_Size-1]
contiendra lesArray_Size
e plus grand élément, et tous les éléments suivants seront plus petit ou égal).Je sais que cela pourrait se faire enterrer, mais voici mon idée pour une variation sur un
radix MSD
.pseudo-code:
La fonction
getMsdIdx(int num)
serait de retour à l'index des chiffres plus importantes (non-nulle). La fonctiongetMsd(int num)
aurait le plus de chiffre significatif. Le d'une fonctionremoveMSD(int num)
permettrait de supprimer les plus importants chiffres d'un nombre et renvoie le nombre (ou de retourner la valeur null si il n'y avait rien à gauche, après le retrait de la plupart chiffre significatif).Une fois cela fait, tout ce qui est à gauche, traverse
mynums
de saisir le top 100 des chiffres. Ce serait quelque chose comme:Je note que, bien que le ci-dessus ressemble, il est grand temps de la complexité, il va vraiment être autour de
O(7*100)
.Une rapide explication de ce que c'est d'essayer de faire:
Essentiellement de ce système est d'essayer d'utiliser tous les chiffres dans un 2d-tableau basé sur l'indice du chiffre dans le nombre, et le chiffre de la valeur. Il les utilise comme index de garder une trace de la façon dont de nombreux numéros de cette valeur ont été insérés dans le tableau. Lorsque 100 a été atteint, il ferme toutes les "branches".
Le temps de cet algorithme est quelque chose comme
O(billion*log(16)*7)+O(100)
. Je peux me tromper à ce sujet. C'est très probablement ce qui nécessite une mise au point comme elle est un peu complexe et j'ai juste écrit sur le haut de ma tête.EDIT: Downvotes sans explication ne sont pas utiles. Si vous pensez que cette réponse est incorrecte, veuillez laisser un commentaire pourquoi. Assez sûr que StackOverflow vous dit même à le faire lorsque vous downvote.
Problème: Trouver les m plus grands éléments de n éléments, n >>> m
La solution la plus simple, qui devrait être évident pour tout le monde est tout simplement m passe de l'algorithme de tri bubble.
puis d'imprimer les n derniers éléments de la matrice.
Cela ne nécessite aucune externes des structures de données, et utilise un algorithme que tout le monde le sait.
Cours d'exécution estimation du temps est O(m*n). La meilleure des réponses à ce jour est de O(n log(m)), donc cette solution n'est pas beaucoup plus cher pour les petites m.
Je ne dis pas que ce ne pouvait pas être amélioré, mais c'est de loin la solution la plus simple.
Récemment que j'ai adapté une théorie que tous les problèmes dans le monde pourrait être résolu en O(1). Et même celui-ci. Il n'était pas clair à partir de la question de savoir quelle est la gamme de nombres. Si les chiffres sont il varie de 1 à 10, puis probablement le top 100 des plus grands nombres de groupe de 10. La chance que le nombre le plus élevé sera pris sur les 1 milliards de chiffres lorsque le plus grand nombre est très faible, à comparer à 1 milliard sont très grands. Je voudrais donc donner cela comme une réponse dans cette interview.