Schreiben Sie ein Programm (oder eine Funktion), das / die je nach Ausführung vier häufig auftretende große O- Zeit-Komplexitäten aufweist. In jeder Form nimmt es eine positive ganze Zahl N an, von der Sie annehmen können, dass sie kleiner als 2 31 ist .
Wenn das Programm in seiner ursprünglichen Form ausgeführt wird, sollte es eine konstante Komplexität aufweisen. Das heißt, die Komplexität sollte Θ (1) oder äquivalent Θ (1 ^ N) sein .
Wenn das Programm umgekehrt und ausgeführt wird, sollte es eine lineare Komplexität haben. Das heißt, die Komplexität sollte Θ (N) oder äquivalent Θ (N ^ 1) sein .
(Dies macht Sinn , daN^1
wird1^N
umgekehrt.)Wenn das Programm verdoppelt , dh auf sich selbst verkettet, und führen Sie es haben sollte exponentielle Komplexität, und zwar 2 N . Das heißt, die Komplexität sollte Θ (2 ^ N) sein .
(Dies ist sinnvoll, da das2
In2^N
das Doppelte des1
In ist1^N
.)Wenn das Programm verdoppelt und umgekehrt und ausgeführt wird, sollte es eine polynomielle Komplexität aufweisen, insbesondere N 2 . Das heißt, die Komplexität sollte Θ (N ^ 2) sein .
(Dies macht Sinn , daN^2
wird2^N
umgekehrt.)
Diese vier Fälle sind die einzigen, die Sie behandeln müssen.
Beachten Sie, dass ich aus Präzisionsgründen die Big-Theta (Θ) -Notation anstelle von Big-O verwende, da die Laufzeiten Ihrer Programme sowohl oben als auch unten durch die erforderlichen Komplexitäten begrenzt sein müssen. Andernfalls würde nur das Schreiben einer Funktion in O (1) alle vier Punkte erfüllen. Es ist nicht so wichtig, die Nuance hier zu verstehen. Wenn Ihr Programm hauptsächlich k * f (N) Operationen für eine Konstante k ausführt, ist dies wahrscheinlich in Θ (f (N)).
Beispiel
Wenn das Originalprogramm wäre
ABCDE
dann sollte das Laufen eine konstante Zeit in Anspruch nehmen. Das heißt, ob der Eingang N 1 oder 2147483647 (2 31 -1) ist oder ein Wert dazwischen, er sollte ungefähr in der gleichen Zeitspanne enden.
Die umgekehrte Version des Programms
EDCBA
sollte in N. ausgedrückt lineare Zeit in Anspruch nehmen. Das heißt, die Zeit, die zum Beenden benötigt wird, sollte in etwa proportional zu N sein. N = 1 dauert also am wenigsten und N = 2147483647 dauert am meisten.
Die doppelte Version des Programms
ABCDEABCDE
Dies bedeutet, dass die Zeit, die zum Beenden benötigt wird, ungefähr proportional zu 2 N sein sollte . Wenn also N = 1 in ungefähr einer Sekunde endet, würde N = 60 länger als das Alter des Universums brauchen, um zu enden. (Nein, du musst es nicht testen.)
Die doppelte und umgekehrte Version des Programms
EDCBAEDCBA
Die Zeit, die zum Beenden benötigt wird, sollte ungefähr proportional zu N * N sein. Wenn also N = 1 in ungefähr einer Sekunde endet, würde N = 60 ungefähr eine Stunde dauern, um zu beenden.
Einzelheiten
Sie müssen zeigen oder argumentieren, dass Ihre Programme in der von Ihnen angegebenen Komplexität ausgeführt werden. Das Eingeben von Zeitdaten ist eine gute Idee, aber versuchen Sie auch zu erklären, warum die Komplexität theoretisch korrekt ist.
Es ist in Ordnung, wenn in der Praxis die Zeiten, die Ihre Programme einnehmen, nicht perfekt für ihre Komplexität (oder sogar deterministisch) repräsentativ sind. zB Eingabe N + 1 läuft manchmal schneller als N.
Die Umgebung, in der Sie Ihre Programme ausführen, spielt eine Rolle. Sie können grundlegende Annahmen darüber treffen, wie populäre Sprachen niemals absichtlich Zeit in Algorithmen verschwenden. Wenn Sie jedoch beispielsweise wissen, dass Ihre Java-Version die Blasensortierung anstelle eines schnelleren Sortieralgorithmus implementiert , sollten Sie dies berücksichtigen, wenn Sie eine Sortierung durchführen .
Bei aller Komplexität wird angenommen, dass es sich um Worst-Case-Szenarien handelt , nicht um Best-Case- oder Average-Case -Szenarien .
Die räumliche Komplexität der Programme spielt keine Rolle, nur die zeitliche Komplexität.
Die Programme können alles ausgeben. Es kommt nur darauf an, dass sie eine positive ganze Zahl N aufnehmen und die richtigen zeitlichen Komplexitäten aufweisen.
Kommentare und mehrzeilige Programme sind erlaubt. (Sie können davon ausgehen, dass dies aus
\r\n
Gründen der\r\n
Windows-Kompatibilität umgekehrt ist .)
Big O Erinnerungen
Vom schnellsten zum langsamsten O(1), O(N), O(N^2), O(2^N)
(Reihenfolge 1, 2, 4, 3 oben).
Langsamere Begriffe dominieren immer, z O(2^N + N^2 + N) = O(2^N)
.
O(k*f(N)) = O(f(N))
für konstante k. Also O(2) = O(30) = O(1)
und O(2*N) = O(0.1*N) = O(N)
.
Erinnere dich an O(N^2) != O(N^3)
und O(2^N) != O(3^N)
.
Ordentliches großes O-Spickzettel.
Wertung
Dies ist normaler Code Golf. Das kürzeste ursprüngliche Programm (die konstante Zeit eins) in Bytes gewinnt.
quelle
n = input(); for i in xrange(n): pass
hat also eine exponentielle Komplexität, weil es2 ** k
Schritte ausführt, bei denenk = log_2(n)
die Eingabegröße ist. Sie sollten klären, ob dies der Fall ist, da sich dadurch die Anforderungen dramatisch ändern.Antworten:
Python 3 , 102 Bytes
Probieren Sie es online!
Dies ist von O (1 ^ n), da dies das Programm tut:
Rückgängig gemacht:
Probieren Sie es online!
Dies ist von O (n ^ 1), da dies das Programm tut:
Verdoppelt:
Probieren Sie es online!
Dies ist von O (2 ^ n), da dies das Programm tut:
Verdoppelt und umgekehrt:
Probieren Sie es online!
Dies ist von O (n ^ 2), da dies das Programm tut:
quelle
input()
?k
der Eingang undl
einer, so dass Sie immer noch rechnen1**k
, richtig? Was sollteO(log(k))
Zeit in Anspruch nehmen , obwohl Sie und ich und jeder im Voraus wissen, dass es eins ist?Perl 5,
827371 + 1 (für -n Flag) = 72 BytesIch bin mir sicher, dass ich dies (viel) mehr Golf spielen kann, aber es ist Schlafenszeit, ich habe genug Zeit mit dem Debuggen verbracht und ich bin trotzdem stolz auf das, was ich bisher habe.
Das Programm selbst verwendet die Eingabe nicht und wertet nur einen String aus, der mit einem Kommentar beginnt, und ersetzt ihn dann durch einen einzelnen String, sodass dies eindeutig in konstanter Zeit erfolgt. Es ist im Grunde gleichbedeutend mit:
Verdoppelt:
Das Bit, das tatsächlich exponentielle Zeit benötigt, ist die zweite Auswertung: Es wertet den Befehl aus
say for(1..2**$_)
, der alle Zahlen von 1 bis 2 ^ N auflistet, was eindeutig exponentielle Zeit benötigt.Rückgängig gemacht:
Dies berechnet (naiv) die Summe der Eingabe, die eindeutig eine lineare Zeit benötigt (da jede Addition in konstanter Zeit erfolgt). Der Code, der tatsächlich ausgeführt wird, entspricht:
Die letzte Zeile ist nur so, dass bei Wiederholung dieser Befehle quadratische Zeit benötigt wird.
Umgekehrt und verdoppelt:
Dies nimmt nun die Summe der Summe der Eingabe (und fügt sie der Summe der Eingabe hinzu, aber was auch immer). Da es
N^2
Hinzufügungen in der Reihenfolge ausführt, dauert dies quadratisch. Es ist im Grunde gleichbedeutend mit:In der zweiten Zeile wird die Summe der Eingaben ermittelt, wobei
N
Additionen ausgeführt werden, während in der vierten Zeilesummation(N)
Additionen ausgeführt werdenO(N^2)
.quelle
$x.=q;##say...
stattdessen$x.=q;#say...
(mit zwei#
statt 1). (Das würde erklären, warum Sie 76 Bytes statt 75 gezählt haben). Außerdem sollten Sie-n
in Ihrem bytecount flag zählen, da Ihr Programm ohne dieses Flag nicht viel anfängt.eval
und dies///
Befehle vertauscht . Wenn du daseval
erste machst, brauchst du nur das eine#
. Guter Fang!#
:$x=~s/#//;
Umgekehrtes Produzieren;//#/s~=x$
, was in Ihrem Kontext nichts bewirkt, wie es bei einem führenden Produkt der Fall wäre#
. (Ich habe es aber nicht getestet). Egal, haben Sie eine +1!Eigentlich 20 Bytes
Probieren Sie es online!
Eingang:
5
Ausgabe:
Rückgängig gemacht:
Probieren Sie es online!
Ausgabe:
Verdoppelt:
Probieren Sie es online!
Ausgabe:
Verdoppelt und umgekehrt:
Probieren Sie es online!
Ausgabe:
Hauptidee
Eigentlich ist eine Stack-basierte Sprache.
abc
ist ein Programm mit O (1 n ) -Komplexität, und sein Doppel hat O (2 n ) -Komplexität.def
ist ein Programm mit O (n 1 ) -Komplexität, und sein Doppel hat O (n 2 ) -Komplexität.Dann ist meine Vorlage
"abc"ƒ"fed"
, woƒ
ausgewertet wird. Auf diese Weise"fed"
wird nicht ausgewertet.Erstellung eines individuellen Programms
Der Pseudocode der ersten Komponente
;(1╖╜ⁿr
:Der Pseudocode der zweiten Komponente
;(1╖╜ⁿ@r
:quelle
Gelee , 20 Bytes
Teilweise inspiriert von Leaky Nuns Actually-Lösung .
Die führenden und nachfolgenden Zeilenumbrüche sind signifikant.
Normal:
Probieren Sie es online!
Eingang:
5
Ausgabe:
Rückgängig gemacht:
Probieren Sie es online!
Eingang:
5
Ausgabe:
Verdoppelt
Probieren Sie es online!
Eingang:
5
Ausgabe:
Verdoppelt und umgekehrt
Probieren Sie es online!
Eingang:
5
Ausgabe:
Erläuterung
Der Schlüssel hier ist in
Ŀ
, was bedeutet, "ruft den Link am Index n als Monade auf". Die Links werden beginnend mit 1 von oben nach unten indiziert, mit Ausnahme des Hauptlinks (des untersten Links).Ŀ
ist ebenfalls modular aufgebaut. Wenn Sie also versuchen, die Verbindungsnummer 7 von 5 Verbindungen anzurufen, rufen Sie tatsächlich die Verbindungsnummer 2 an.Der in diesem Programm aufgerufene Link ist immer der Link mit Index 10 (
⁵
), unabhängig von der Programmversion. Welcher Link sich jedoch auf Index 10 befindet, hängt von der Version ab.Das
⁵
, das nach jedem angezeigt wird,Ŀ
ist dort, also bricht es nicht, wenn es aufgehoben wird. Das Programm wird beim Parsen fehlschlagen, wenn es vorher keine Nummer gibtĿ
. Ein⁵
After zu haben, ist ein fehl am Platz, der direkt zum Ausgang geht.In der Originalversion wird der Link
‘
aufgerufen, der n + 1 berechnet.In der umgekehrten Version wird der Link aufgerufen
R
, der den Bereich 1 .. n generiert.Die doppelte Version ruft den Link auf
2*R
, der 2 n berechnet und den Bereich 1 .. 2 n generiert .Die doppelte und umgekehrte Version ruft den Link auf
²R
, der n 2 berechnet und den Bereich 1 .. n 2 generiert .quelle
Befunge-98 , 50 Bytes
Normal
Dies ist bei weitem das einfachste Programm der 4 - die einzigen Befehle, die ausgeführt werden, sind die folgenden:
Dieses Programm führt einige irrelevante Aktionen aus, bevor Sie einen "Rechts abbiegen" -Befehl (
]
) und einen Pfeil drücken . Dann drückt es 2 "Eingabe" -Befehle. Da die Eingabe nur eine Zahl enthält und TIO&
s behandelt , wird das Programm nach 60 Sekunden beendet. Wenn es 2 Eingänge gibt (und weil ich das kann, ohne Bytes hinzuzufügen), würde die IP in die Funktion "Programm beenden" hochfahren.Probieren Sie es online!
Rückgängig gemacht
Dieser ist etwas komplizierter. Die relevanten Befehle lauten wie folgt:
das ist äquivalent zu
Der wichtige Teil hier ist das
:. 1-:!k@
Bit. Dies ist nützlich, da wir die gewünschte Komplexität erhalten können, solange wir die richtige Komplexität auf den Stapel schieben, bevor wir sie in einer niedrigeren Zeitkomplexität ausführen. Dies wird in den verbleibenden 2 Programmen auf diese Weise verwendet.Probieren Sie es online!
Verdoppelt
Und die relevanten Befehle sind:
Dieses Programm besteht aus 2 Schleifen. Erstens folgt es dem gleichen Pfad wie das normale Programm, das 1 und N auf den Stapel legt, aber anstatt auf den zweiten zu
&
wechseln, springt die IP über einen Kommentar in eine Schleife, die Folgendes überträgt2^N
:Die anderen Bits in Zeile 4 werden mit
;
s übersprungenNachdem (2 ^ N) auf den Stapel geschoben wurde, bewegen wir uns eine Zeile nach unten in die oben erwähnte Druckschleife. Aufgrund der ersten Schleife ist die Zeitkomplexität Θ (N + 2 ^ N), dies reduziert sich jedoch auf Θ (2 ^ N).
Probieren Sie es online!
Verdoppelt und umgekehrt
Die relevanten Befehle:
Dies funktioniert fast identisch mit dem umgekehrten Programm, aber das Programm
N^2
wird nicht aus dem Stapel entfernt, da die erste Zeile der zweiten Kopie des Programms an die letzte Zeile der ersten angefügt wird, was bedeutet, dass der Befehl drop ($
) niemals ausgeführt wird , so gehen wir in die Druckschleife mitN^2
auf der Oberseite des Stapels.Probieren Sie es online!
quelle