Un de mes amis est en entrevue pour un emploi. L'une des questions de l'entrevue m'a fait réfléchir, je voulais juste un commentaire.
Il existe 2 entiers non négatifs: i et j. Étant donné l'équation suivante, trouvez une solution (optimale) pour itérer sur i et j de manière à ce que la sortie soit triée.
2^i * 5^j
Ainsi, les premiers tours ressembleraient à ceci:
2^0 * 5^0 = 1
2^1 * 5^0 = 2
2^2 * 5^0 = 4
2^0 * 5^1 = 5
2^3 * 5^0 = 8
2^1 * 5^1 = 10
2^4 * 5^0 = 16
2^2 * 5^1 = 20
2^0 * 5^2 = 25
Essayez comme je pourrais, je ne vois pas de modèle. Tes pensées?
algorithm
optimization
hamming-numbers
smooth-numbers
Chris Eberle
la source
la source
2^2 < 5
mais2^3 > 5
donc à ce point vous augmentez j. Je pense que vous pouvez produire la sortie en O (n) plutôt qu'en O (nlgn). @ tom-zynch deux boucles imbriquées est O (n ^ 2). Cette question est très valableRéponses:
Dijkstra tire une solution éloquente dans "Une discipline de la programmation". Il attribue le problème à Hamming. Voici ma mise en œuvre de la solution de Dijkstra.
la source
voici une façon plus raffinée de le faire (plus raffinée que ma réponse précédente, c'est-à-dire):
imaginez que les nombres sont placés dans une matrice:
ce que vous devez faire est de «parcourir» cette matrice, en commençant par
(0,0)
. Vous devez également garder une trace de vos prochains mouvements possibles. Lorsque vous commencez par(0,0)
vous n'avez que deux options: soit(0,1)
ou(1,0)
: puisque la valeur de(0,1)
est plus petite, vous choisissez cela. puis faites de même pour votre prochain choix(0,2)
ou(1,0)
. , Vous avez jusqu'à présent la liste suivante:1, 2, 4
. Votre prochain mouvement est(1,0)
que la valeur y est inférieure à(0,3)
. Cependant, vous avez maintenant trois choix pour votre prochain mouvement: soit(0,3)
, ou(1,1)
, ou(2,0)
.Vous n'avez pas besoin de la matrice pour obtenir la liste, mais vous devez garder une trace de tous vos choix (c'est-à-dire que lorsque vous atteignez 125+, vous aurez 4 choix).
la source
j
vérifie pour chaque sortie 1j ~ n^0.5
pour la n-ième valeur d'une séquence, puisque lesn
valeurs remplissent une zone sur lei x j
plan. Donc, cet algo est leO(n^1.5)
temps, avec l'O(n^0.5)
espace. Mais il existe un algorithme de temps linéaire avec le même espace complxty den^0.5
, et l'algo mini-tas de la réponse ci-dessous est leO(n*log(n))
temps avec le mêmen^0.5
espace.Utilisez un tas min.
Mettez 1.
extrait-Min. Dites que vous obtenez x.
Poussez 2x et 5x dans le tas.
Répéter.
Au lieu de stocker x = 2 ^ i * 5 ^ j, vous pouvez stocker (i, j) et utiliser une fonction de comparaison personnalisée.
la source
Une solution basée sur FIFO nécessite moins de capacité de stockage. Code Python.
production:
la source
C'est très facile à faire
O(n)
dans les langages fonctionnels. La listel
des2^i*5^j
nombres peut être simplement définie comme1
et ensuite2*l
et5*l
fusionnée. Voici à quoi cela ressemble dans Haskell:La
merge
fonction vous donne une nouvelle valeur en temps constant. Il en va de mêmemap
et par conséquentl
.la source
union
place, car elle supprime les doublons.merge
, dans le cadre demergesort
, doit conserver les doublons provenant de ses deux séquences d'entrée. Voir leData.List.Ordered
paquet pour les trucs connexes.Data.List.Ordered.union
. Cela en fait une ligne:xs = 1 : union (map (2*) xs) (map (5*) xs)
[1, 2, 4, 5,...]
donc il comprend5*4
.Data.List.Ordered.union
fonction. À ne pas confondre avecData.List.union
.Vous devez garder une trace de leurs exposants individuels et de leurs sommes
vous devez donc commencer par
f(0,0) --> 1
incrémenter l'un d'entre eux:nous savons donc que 2 est le suivant - nous savons également que nous pouvons incrémenter l'exposant de i jusqu'à ce que la somme dépasse 5.
Vous continuez à aller et venir comme ça jusqu'à ce que vous soyez à votre nombre de tours défini.
la source
f(*,2)
simplement parce que vous l'avez trouvéf(a1,b+1)>f(a2,b)
. Une approche incrémentielle générera éventuellement un nombre illimité de paires voisines de la région que vous avez déjà sortie.En utilisant la programmation dynamique, vous pouvez le faire en O (n). La vérité fondamentale est qu'aucune valeur de i et j ne peut nous donner 0, et pour obtenir 1 les deux valeurs doivent être 0;
Chaque fois que vous appelez cette fonction, vérifiez si i et j sont définis, s'ils ne sont pas nuls, puis remplissez
TwoCount
etFiveCount
Réponse C ++. Désolé pour le mauvais style de codage, mais je suis pressé :(
Évidemment, vous pouvez utiliser des structures de données autres que des tableaux pour augmenter dynamiquement votre stockage, etc. Ceci est juste un croquis pour prouver que cela fonctionne.
la source
O(exp(sqrt(n)))
, pour produire lesn
nombres de la séquence. Un algorithme linéaire existe, par exemple tel que donné par ThomasAhle.O(n)
signifien
être la dernière valeur, pas le nombre d'articles imprimés, ce qui n'est pas correct. Je ne sais pas comment fonctionnent les langages fonctionnels ou comment la fusion fonctionne en temps constant, mais sa réponse a obtenu mon vote positifPourquoi ne pas essayer de regarder cela de l'autre côté. Utilisez un compteur pour tester les réponses possibles par rapport à la formule originale. Désolé pour le pseudo code.
la source
O(4^sqrt(n))
parce que lenth
numéro de la séquence est d'environ cette taille.Il s'agit de l'entrée pertinente chez OEIS.
Il semble possible d'obtenir la séquence ordonnée en générant les premiers termes, disons
puis, à partir du deuxième terme, multiplier par 4 et 5 pour obtenir les deux suivants
etc...
Intuitivement, cela semble correct, mais il manque bien sûr une preuve.
la source
Vous savez que log_2 (5) = 2,32. De cela, nous notons que 2 ^ 2 <5 et 2 ^ 3> 5.
Maintenant, regardez une matrice de réponses possibles:
Maintenant, pour cet exemple, choisissez les nombres dans l'ordre. Là, la commande serait:
Notez que chaque ligne commence 2 colonnes derrière la ligne qui la commence. Par exemple, i = 0 j = 1 vient directement après i = 2 j = 0.
Un algorithme que nous pouvons déduire de ce modèle est donc (supposons j> i):
REMARQUE: le code ici limite les valeurs des exposants de i et j à moins de 10. Vous pouvez facilement étendre cet algorithme pour qu'il tienne dans toutes les autres limites arbitraires.
REMARQUE: le temps d'exécution de cet algorithme est O (n) pour les n premières réponses.
REMARQUE: la complexité spatiale pour cet algorithme est O (1)
la source
Ma mise en œuvre est basée sur les idées suivantes:
Exemple:
Code en Java:
la source
calculer les résultats et les mettre dans une liste triée, avec les valeurs pour
i
etj
la source
2^n*5^n
mais pas2^(n+1)*5^(n-1)
ce qui est plus petit.i
et vosj
, n'est-ce pas? Sinon, vous n'obtiendrez jamais l'état de tri, et par conséquent, vous ne retournerez jamais une seule valeur. Mais quelle que soit la limite quen
vous choisissez, votre liste sera imparfaite.i
etj
.2^i*5^j
valeurs, puis les triez. Si vous n'avez pas un nombre limité de "résultats", comment allez-vous arriver à l'étape de tri?L'algorithme implémenté par user515430 par Edsger Dijkstra (http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF) est probablement aussi rapide que possible. J'appelle chaque numéro qui est une forme de
2^i * 5^j
"numéro spécial". Maintenant, la réponse de Vlads seraitO(i*j)
mais avec un double algorithme, un pour générer les numéros spéciauxO(i*j)
et un pour les trier (selon l'article lié égalementO(i*j)
.Mais vérifions l'algorithme de Dijkstra (voir ci-dessous). Dans ce cas,
n
la quantité de nombres spéciaux que nous générons est donc égale ài*j
. Nous faisons une boucle une fois,1 -> n
et dans chaque boucle nous effectuons une action constante. Donc, cet algorithme l'est égalementO(i*j)
. Et avec une constante assez rapide aussi.Mon implémentation en C ++ avec GMP (wrapper C ++), et la dépendance sur
boost::lexical_cast
, bien que cela puisse être facilement supprimé (je suis paresseux, et qui n'utilise pas Boost?). Compilé avecg++ -O3 test.cpp -lgmpxx -o test
. Sur Q6600, Ubuntu 10.10time ./test 1000000
donne1145ms
.la source
Si vous dessinez une matrice avec i comme ligne et j comme colonne, vous pouvez voir le modèle. Commencez par i = 0 puis parcourez simplement la matrice en remontant de 2 lignes et à droite de 1 colonne jusqu'à atteindre le haut de la matrice (j> = 0). Alors allez i + 1, etc ...
Donc pour i = 7 vous voyagez comme ceci:
Et pour i = 8:
Le voici en Java allant jusqu'à i = 9. Il imprime la position de la matrice (i, j) et la valeur.
la source
Mon intuition :
Si je prends la valeur initiale comme 1 où i = 0, j = 0, alors je peux créer les nombres suivants comme (2 ^ 1) (5 ^ 0), (2 ^ 2) (5 ^ 0), (2 ^ 0) * (5 ^ 1), ... soit 2,4,5 ..
Disons qu'à tout moment, mon nombre est x. alors je peux créer les numéros suivants de la manière suivante:
Explication :
Essai
Commençons par x = 1.
Les trois nombres suivants sont 1 * 2, 1 * 4, 1 * 5 [2,4,5]; Arr [1,2,4,5]
Maintenant x = 2
Les trois nombres suivants sont [4,8,10] {Puisque 4 est déjà arrivé, nous l'ignorerons} [8,10]; Arr [1,2,4,5,8,10]
Maintenant x = 4
Les trois numéros suivants [8,16,20] {8 sont déjà apparus ignorer} [16,20] Arr [1,2,4,5,8,10,16,20]
x = 5
Trois nombres suivants [10,20,25] {10,20} déjà donc [25] est ajouté Arr [1,2,4,5,8,10,16,20,25]
Condition de résiliation
Une analyse
la source
J'étais juste curieux de savoir à quoi s'attendre la semaine prochaine et j'ai trouvé cette question.
Je pense que l'idée est de 2 ^ i n'augmente pas dans ce grand pas comme 5 ^ j. Augmentez donc i tant que le prochain pas j ne serait pas plus grand.
L'exemple en C ++ (Qt est facultatif):
Le résultat:
la source
Voici ma solution
Résultat :
la source
Je sais que je me trompe probablement, mais il y a ici une heuristique très simple car elle n'implique pas beaucoup de nombres comme 2,3,5. Nous savons que pour tout i, j 2 ^ i * 5 ^ j la séquence suivante serait 2 ^ (i-2) * 5 ^ (j + 1). Être un google q doit avoir une solution simple.
Cela produit une sortie comme:
la source
Si vous passez par ce qui se passe réellement lorsque nous incrémentons i ou j dans l'expression
2^i * 5^j
, vous multipliez soit par un autre 2, soit par un autre 5. Si nous reformulons le problème comme - étant donné une valeur particulière de i et j, comment trouveriez-vous la suivante plus grande valeur, la solution devient apparente.Voici les règles que nous pouvons énumérer assez intuitivement:
i > 1
) dans l'expression, nous devrions les remplacer par un 5 pour obtenir le prochain plus grand nombre. Ainsi,i -= 2
etj += 1
.j > 0
), nous devons le remplacer par trois 2. Alorsj -= 1
eti += 3
.i += 1
.Voici le programme en Ruby:
la source
Si nous sommes autorisés à utiliser java Collection, nous pouvons avoir ces nombres dans O (n ^ 2)
Ici, powerLimit doit être initialisé très soigneusement !! En fonction du nombre de numéros que vous souhaitez.
la source
Voici ma tentative avec Scala:
Production:
la source