Ecrivez un programme (ou une fonction) qui présente quatre grandes complexités de temps O communes, en fonction de la manière dont il est exécuté. Quelle que soit sa forme, il prend un entier positif N que vous pouvez supposer inférieur à 2 31 .
Lorsque le programme est exécuté dans sa forme d' origine, sa complexité doit être constante . C'est-à-dire que la complexité devrait être (1) ou, de manière équivalente, (1 ^ N) .
Lorsque le programme est inversé et exécuté, il doit avoir une complexité linéaire . C'est-à-dire que la complexité devrait être (N) ou, de manière équivalente, Θ (N ^ 1) .
(Cela a du sens puisqueN^1
est1^N
inversé.)Lorsque le programme est doublé , ce concaténé à lui - même, et l' exécuter devrait avoir exponentielle la complexité, en particulier 2 N . C'est-à-dire que la complexité devrait être (2 ^ N) .
(Cela a du sens puisque l'2
in2^N
est le double de l'1
in1^N
.)Lorsque le programme est doublé , inversé et exécuté, il doit présenter une complexité polynomiale , en particulier N 2 . C'est-à-dire que la complexité devrait être (N ^ 2) .
(Cela a du sens puisqueN^2
est2^N
inversé.)
Ces quatre cas sont les seuls dont vous avez besoin.
Notez que pour plus de précision, j'utilise la notation thêta grosse () au lieu de la lettre grand O car les exécutions de vos programmes doivent être limitées à la fois par le haut et par le bas par la complexité requise. Sinon, écrire une fonction dans O (1) satisferait les quatre points. Il n’est pas très important de comprendre la nuance ici. Principalement, si votre programme effectue des opérations k * f (N) pour une constante k alors il est probable qu'il se trouve dans Θ (f (N)).
Exemple
Si le programme initial était
ABCDE
puis cela devrait prendre un temps constant. En d'autres termes, que l'entrée N soit égale à 1 ou 2147483647 (2 31 -1) ou à une valeur quelconque, elle doit se terminer à peu près dans le même temps.
La version inversée du programme
EDCBA
devrait prendre un temps linéaire en termes de N. Autrement dit, le temps nécessaire pour terminer doit être approximativement proportionnel à N. Donc, N = 1 prend le moins de temps et N = 2147483647, le plus.
La version doublée du programme
ABCDEABCDE
devrait prendre le temps de deux à la N en termes de N. C'est, le temps qu'il faut mettre fin devrait être à peu près proportionnelle à 2 N . Donc, si N = 1 se termine dans environ une seconde, N = 60 prendra plus de temps que l'âge de l'univers pour se terminer. (Non, vous n'avez pas à le tester.)
La version doublée et inversée du programme
EDCBAEDCBA
devrait prendre un temps carré en termes de N. Autrement dit, le temps nécessaire pour terminer doit être à peu près proportionnel à N * N. Donc, si N = 1 se termine dans environ une seconde, N = 60 prend environ une heure pour se terminer.
Détails
Vous devez montrer ou argumenter que vos programmes fonctionnent dans les complexités que vous dites être. Donner des données temporelles est une bonne idée, mais essayez également d’expliquer pourquoi la complexité est théoriquement correcte.
C'est bien si, en pratique, les temps que prennent vos programmes ne sont pas parfaitement représentatifs de leur complexité (ou même déterministes). Par exemple, l'entrée N + 1 peut parfois courir plus vite que N.
L'environnement dans lequel vous exécutez vos programmes est important. Vous pouvez faire des suppositions de base sur le fait que les langages populaires ne perdent jamais intentionnellement du temps dans des algorithmes. Par exemple, si vous savez que votre version de Java implémente le tri à bulle au lieu d'un algorithme de tri plus rapide , vous devez en tenir compte si vous effectuez un tri. .
Pour toutes les complexités, supposons ici que nous parlons des pires scénarios , et non des cas optimaux ou moyens.
La complexité spatiale des programmes n'a pas d'importance, seule la complexité temporelle.
Les programmes peuvent sortir n'importe quoi. Il importe seulement qu’ils prennent le nombre entier positif N et aient les complexités temporelles correctes.
Les commentaires et les programmes multilignes sont autorisés. (Vous pouvez supposer que la compatibilité avec Windows
\r\n
est inversée\r\n
.)
Big O Rappels
Du plus rapide au plus lent O(1), O(N), O(N^2), O(2^N)
(ordre 1, 2, 4, 3 ci-dessus).
Les termes les plus lents dominent toujours, par exemple O(2^N + N^2 + N) = O(2^N)
.
O(k*f(N)) = O(f(N))
pour constante k. Alors O(2) = O(30) = O(1)
et O(2*N) = O(0.1*N) = O(N)
.
Rappelez O(N^2) != O(N^3)
- vous et O(2^N) != O(3^N)
.
Notation
C'est un code de golf normal. Le programme original le plus court (le temps constant un) en octets l'emporte.
la source
n = input(); for i in xrange(n): pass
a une complexité exponentielle, car il prend des2 ** k
étapes, oùk = log_2(n)
est la taille d'entrée. Vous devez préciser si c'est le cas, car cela change radicalement les exigences.Réponses:
Python 3 , 102 octets
Essayez-le en ligne!
C'est de O (1 ^ n), puisque c'est ce que fait le programme:
Renversé:
Essayez-le en ligne!
C'est de O (n ^ 1), puisque c'est ce que fait le programme:
Doublé:
Essayez-le en ligne!
C'est de O (2 ^ n), puisque c'est ce que fait le programme:
Doublé et inversé:
Essayez-le en ligne!
C'est de O (n ^ 2), puisque c'est ce que fait le programme:
la source
input()
?k
s’agit de l’entrée, etl
c’est le cas, vous calculez donc toujours1**k
, non? Ce qui devrait prendre duO(log(k))
temps, malgré le fait que vous et moi et tout le monde sachions d'avance qu'il en est un?Perl 5,
827371 + 1 (pour l'indicateur -n) = 72 octetsJe suis certain de pouvoir jouer au golf beaucoup plus, mais il est l'heure d'aller au lit, j'ai passé assez de temps à déboguer tel quel et je suis fier de ce que j'ai jusqu'ici.
Le programme lui-même n'utilise pas l'entrée, il évalue simplement une chaîne commençant par un commentaire, puis effectue une substitution de chaîne unique, ce qui est clairement en temps constant. C'est fondamentalement équivalent à:
Doublé:
Le bit qui prend réellement un temps exponentiel est la deuxième évaluation: il évalue la commande
say for(1..2**$_)
, qui répertorie tous les nombres de 1 à 2 ^ N, ce qui prend clairement un temps exponentiel.Renversé:
Ceci (naïvement) calcule la somme de l'entrée, ce qui prend clairement un temps linéaire (puisque chaque addition est en temps constant). Le code qui est réellement exécuté est équivalent à:
La dernière ligne est juste pour que, lorsque ces commandes sont répétées, cela prenne du temps quadratique.
Renversé et doublé:
Ceci prend maintenant la somme de la somme de l'entrée (et l'ajoute à la somme de l'entrée, mais peu importe). Comme cela fait des
N^2
ajouts d' ordre , cela prend du temps quadratique. C'est fondamentalement équivalent à:La deuxième ligne trouve la somme des entrées, en effectuant des
N
ajouts, tandis que la quatrième effectue dessummation(N)
ajouts, ce qui estO(N^2)
.la source
$x.=q;##say...
au lieu de$x.=q;#say...
bien (avec deux#
au lieu de 1). (Cela expliquerait pourquoi vous avez compté 76 octets au lieu de 75). De plus, vous devriez compter le-n
drapeau dans votre compte intermédiaire, car votre programme ne fait pas grand chose sans.eval
less///
commandes et. Si vous faites leeval
premier, vous n’avez besoin que du premier#
. Bonne prise!#
:$x=~s/#//;
produit inversé;//#/s~=x$
, ce qui dans votre contexte ne fait rien, comme il le ferait avec un interlocuteur principal#
. (Je ne l'ai pas testé cependant). Quoi qu'il en soit, ayez un +1!En fait , 20 octets
Essayez-le en ligne!
Contribution:
5
Sortie:
Renversé:
Essayez-le en ligne!
Sortie:
Doublé:
Essayez-le en ligne!
Sortie:
Doublé et inversé:
Essayez-le en ligne!
Sortie:
Idée principale
En fait, c'est un langage basé sur la pile.
abc
est un programme qui a une complexité O (1 n ), et son double a une complexité O (2 n ).def
est un programme qui a une complexité O (n 1 ) et son double a une complexité O (n 2 ).Ensuite, ma soumission est
"abc"ƒ"fed"
, oùƒ
est évaluer. De cette façon,"fed"
ne sera pas évalué.Génération de programme individuel
Le pseudocode du premier composant
;(1╖╜ⁿr
:Le pseudocode du deuxième composant
;(1╖╜ⁿ@r
:la source
Gelée , 20 octets
Inspiré en partie par la solution Leaky Nun's Actually .
Les nouvelles lignes de début et de fin sont significatives.
Ordinaire:
Essayez-le en ligne!
Contribution:
5
Sortie:
Renversé:
Essayez-le en ligne!
Contribution:
5
Sortie:
Doublé
Essayez-le en ligne!
Contribution:
5
Sortie:
Doublé et renversé
Essayez-le en ligne!
Contribution:
5
Sortie:
Explication
La clé est ici
Ŀ
, ce qui signifie "appelle le lien à l'index n en tant que monade". Les liens sont indexés de haut en bas à partir de 1, à l’exclusion du lien principal (le plus bas).Ŀ
est également modulaire, donc si vous essayez d’appeler le lien numéro 7 sur 5 liens, vous appellerez en fait le lien 2.Le lien appelé dans ce programme est toujours celui de l'index 10 (
⁵
), quelle que soit sa version. Cependant, le lien à l'index 10 dépend de la version.Le
⁵
qui apparaît après chaqueĿ
est là pour qu'il ne casse pas lorsqu'il est inversé. Le programme affichera une erreur lors de l'analyse s'il n'y a pas de numéro avantĿ
. Avoir un⁵
après c'est un nilad hors de propos, qui va directement à la sortie.La version d'origine appelle le lien
‘
, qui calcule n + 1.La version inversée appelle le lien
R
, qui génère la plage 1 .. n.La version doublée appelle le lien
2*R
, qui calcule 2 n et génère la plage 1 .. 2 n .La version doublée et inversée appelle le lien
²R
, qui calcule n 2 et génère la plage 1 .. n 2 .la source
Befunge-98 , 50 octets
Ordinaire
C'est de loin le programme le plus simple des 4 - les seules commandes exécutées sont les suivantes:
Ce programme effectue des opérations irrévocables avant de frapper une commande "tournez à droite" (
]
) et une flèche. Ensuite, il frappe 2 commandes "prendre entrée". Comme il n'y a qu'un seul nombre en entrée et à cause de la façon dont TIO traite les&
s, le programme se ferme après 60 secondes. S'il y a 2 entrées (et parce que je peux sans ajouter d'octets), l'IP irait dans la fonction "fin du programme".Essayez-le en ligne!
Renversé
Celui-ci est un peu plus compliqué. les commandes pertinentes sont les suivantes:
ce qui équivaut à
La partie importante ici est le
:. 1-:!k@
bit. C'est utile car tant que nous plaçons la complexité correcte sur la pile avant d'exécuter dans une complexité temporelle inférieure, nous pouvons obtenir celle désirée. Ceci sera utilisé dans les 2 programmes restants de cette manière.Essayez-le en ligne!
Doublé
Et les commandes pertinentes sont:
Ce programme se déroule en 2 boucles. Premièrement, il suit le même chemin que le programme normal, qui insère 1 et N dans la pile, mais au lieu d’enrouler autour de la seconde
&
, l’IP saute par-dessus un commentaire dans une boucle qui pousse2^N
:Les autres bits de la ligne 4 sont sautés en utilisant
;
sAprès que (2 ^ N) soit poussé sur la pile, nous descendons d’une ligne dans la boucle d’impression susmentionnée. En raison de la première boucle, la complexité temporelle est (N + 2 ^ N), mais elle se réduit à Θ (2 ^ N).
Essayez-le en ligne!
Doublé et renversé
Les commandes pertinentes:
Ceci fonctionne presque à l'identique du programme inversé, mais
N^2
n'est pas extrait de la pile, car la première ligne de la deuxième copie du programme est ajoutée à la dernière ligne de la première, ce qui signifie que la commande de suppression ($
) n'est jamais exécutée. , nous passons donc dans la boucle d’impression avecN^2
en haut de la pile.Essayez-le en ligne!
la source