Napisz program (lub funkcję), który wykazuje cztery typowe złożone złożoności czasu O w zależności od tego, jak jest uruchamiany. W dowolnej formie przyjmuje dodatnią liczbę całkowitą N, którą możesz założyć, że jest mniejsza niż 2 31 .
Gdy program jest uruchamiany w oryginalnej formie, powinien mieć stałą złożoność. Oznacza to, że złożoność powinna wynosić Θ (1) lub równoważnie Θ (1 ^ N) .
Gdy program zostanie odwrócony i uruchomiony, powinien mieć złożoność liniową . Oznacza to, że złożoność powinna wynosić Θ (N) lub równoważnie Θ (N ^ 1) .
(Ma to sens, ponieważN^1
jest1^N
odwrócone).Gdy program zostanie podwojona , czyli łączone do siebie i uruchomić powinien mieć wykładniczą złożoność, a konkretnie 2 N . Oznacza to, że złożoność powinna wynosić Θ (2 ^ N) .
(Ma to sens, ponieważ2
in2^N
jest podwójnie1
in1^N
.)Gdy program zostanie podwojona i odwrócone i uruchomić powinien mieć wielomian złożoności, a konkretnie N 2 . Oznacza to, że złożoność powinna wynosić Θ (N ^ 2) .
(Ma to sens, ponieważN^2
jest2^N
odwrócone).
Te cztery przypadki są jedynymi, z którymi musisz sobie poradzić.
Zauważ, że dla dokładności używam dużej theta (Θ) zamiast dużej O, ponieważ środowiska wykonawcze programów muszą być ograniczone zarówno powyżej, jak i poniżej wymaganymi złożonościami. W przeciwnym razie samo napisanie funkcji w O (1) spełni wszystkie cztery punkty. Nie jest zbyt ważne, aby zrozumieć niuans tutaj. Głównie, jeśli twój program wykonuje operacje k * f (N) dla pewnej stałej k, to prawdopodobnie jest to Θ (f (N)).
Przykład
Jeśli oryginalny program był
ABCDE
następnie uruchomienie powinno zająć cały czas. To znaczy, czy wejście N wynosi 1, czy 2147483647 (2 31 -1), czy jakakolwiek wartość pomiędzy nimi, powinno zakończyć się mniej więcej w tym samym czasie.
Odwrócona wersja programu
EDCBA
powinien zająć czas liniowy w odniesieniu do N. To znaczy, czas potrzebny do zakończenia powinien być w przybliżeniu proporcjonalny do N. Tak więc N = 1 zajmuje najmniej czasu, a N = 2147483647 zajmuje najwięcej.
Podwójna wersja programu
ABCDEABCDE
Należy wziąć dwa-do-N godziny w kategoriach N. Oznacza to, że czas potrzebny do rozwiązania powinny być w przybliżeniu proporcjonalna do 2 N . Więc jeśli N = 1 kończy się w ciągu około sekundy, N = 60 zajęłoby więcej niż wiek wszechświata, aby zakończyć. (Nie, nie musisz tego testować.)
Podwojona i odwrócona wersja programu
EDCBAEDCBA
powinien zająć do kwadratu czas w kategoriach N. Oznacza to, że czas potrzebny do zakończenia powinien być w przybliżeniu proporcjonalny do N * N. Więc jeśli N = 1 zakończy się za około sekundę, N = 60 zajmie około godziny.
Detale
Musisz pokazać lub argumentować, że twoje programy działają w złożoności, o której mówisz, że są. Podanie pewnych danych dotyczących czasu jest dobrym pomysłem, ale spróbuj także wyjaśnić, dlaczego teoretycznie złożoność jest poprawna.
Jest w porządku, jeśli w praktyce czasy, w których twoje programy nie są w pełni reprezentatywne dla ich złożoności (a nawet determinizmu). np. wejście N + 1 może czasami działać szybciej niż N.
Środowisko, w którym uruchamiasz swoje programy, ma znaczenie. Możesz przyjąć podstawowe założenia dotyczące tego, że popularne języki nigdy celowo nie marnują czasu na algorytmy, ale na przykład, jeśli wiesz, że twoja konkretna wersja Java implementuje sortowanie bąbelkowe zamiast szybszego algorytmu sortowania , powinieneś wziąć to pod uwagę, jeśli wykonujesz jakiekolwiek sortowanie .
Dla wszystkich zawiłości tutaj załóżmy, że mówimy o scenariuszach najgorszych przypadków , a nie najlepszych lub średnich.
Złożoność przestrzenna programów nie ma znaczenia, tylko złożoność czasowa.
Programy mogą wysyłać cokolwiek. Liczy się tylko to, że przyjmują dodatnią liczbę całkowitą N i mają prawidłową złożoność czasową.
Komentarze i programy wieloliniowe są dozwolone. (Możesz założyć, że
\r\n
odwrócona jest\r\n
zgodna z Windows).
Wielkie przypomnienia
Od najszybszego do najwolniejszego O(1), O(N), O(N^2), O(2^N)
(kolejność 1, 2, 4, 3 powyżej).
Wolniejsze terminy zawsze dominują, np O(2^N + N^2 + N) = O(2^N)
.
O(k*f(N)) = O(f(N))
dla stałej k. Więc O(2) = O(30) = O(1)
i O(2*N) = O(0.1*N) = O(N)
.
Pamiętaj O(N^2) != O(N^3)
i O(2^N) != O(3^N)
.
Punktacja
To normalny kod golfowy. Najkrótszy oryginalny program (czas stały) w bajtach wygrywa.
źródło
n = input(); for i in xrange(n): pass
ma wykładniczą złożoność, ponieważ wykonuje2 ** k
kroki, gdziek = log_2(n)
jest wielkość wejściowa. Należy wyjaśnić, czy tak jest, ponieważ radykalnie zmienia to wymagania.Odpowiedzi:
Python 3 , 102 bajty
Wypróbuj online!
Jest to O (1 ^ n), ponieważ to właśnie robi program:
Wywrócony:
Wypróbuj online!
Jest to O (n ^ 1), ponieważ to właśnie robi program:
Podwojony:
Wypróbuj online!
Jest to O (2 ^ n), ponieważ to właśnie robi program:
Podwojone i odwrócone:
Wypróbuj online!
Jest to O (n ^ 2), ponieważ to właśnie robi program:
źródło
input()
?k
czy dane wejściowel
są jedno, więc nadal pracujesz1**k
, prawda? Co powinno zająć trochęO(log(k))
czasu, mimo że ty, ja i wszyscy wiemy z góry, że to jedno?Perl 5,
827371 + 1 (dla flagi -n) = 72 bajtyJestem pewien, że mogę grać w golfa (dużo) bardziej, ale przed snem spędziłem wystarczająco dużo czasu na debugowaniu i jestem dumny z tego, co do tej pory mam.
Sam program nie korzysta z danych wejściowych, po prostu ocenia ciąg rozpoczynający się od komentarza, a następnie dokonuje podstawienia pojedynczego ciągu, więc jest to wyraźnie w stałym czasie. Jest to w zasadzie odpowiednik:
Podwojony:
Bit, który faktycznie zajmuje czas wykładniczy, jest drugim eval: ocenia polecenie
say for(1..2**$_)
, które wyświetla wszystkie liczby od 1 do 2 ^ N, co wyraźnie zajmuje czas wykładniczy.Wywrócony:
To (naiwnie) oblicza sumę danych wejściowych, co wyraźnie zajmuje czas liniowy (ponieważ każde dodawanie odbywa się w stałym czasie). Uruchomiony kod jest równoważny z:
Ostatni wiersz jest po prostu taki, że powtórzenie tych poleceń zajmie kwadratowy czas.
Odwrócony i podwojony:
To teraz bierze sumowanie sumy danych wejściowych (i dodaje je do sumy danych wejściowych, ale cokolwiek innego). Ponieważ porządkuje
N^2
dodatki, zajmuje to kwadratowy czas. Jest to w zasadzie odpowiednik:Drugi wiersz zawiera podsumowanie danych wejściowych,
N
dodając dodatki, podczas gdy czwartysummation(N)
dodaje, czyliO(N^2)
.źródło
$x.=q;##say...
zamiast$x.=q;#say...
(z dwoma#
zamiast 1). (To by wyjaśniało, dlaczego policzyłeś 76 bajtów zamiast 75). Powinieneś także liczyć-n
flagę na swoim bytecount, ponieważ twój program nie robi wiele bez niej.eval
as///
polecenia. Jeśli zrobiszeval
pierwszy, potrzebujesz tylko tego#
. Dobry chwyt!#
:$x=~s/#//;
odwrotne produkcje;//#/s~=x$
, które w twoim kontekście nic nie robią, tak jak przy wiodącym#
. (Nie przetestowałem tego jednak). Niezależnie od tego, masz +1!Właściwie 20 bajtów
Wypróbuj online!
Wejście:
5
Wynik:
Wywrócony:
Wypróbuj online!
Wynik:
Podwojony:
Wypróbuj online!
Wynik:
Podwojone i odwrócone:
Wypróbuj online!
Wynik:
Główny pomysł
W rzeczywistości jest językiem stosowym.
abc
jest programem o złożoności O (1 n ), a jego podwójność ma złożoność O (2 n ).def
jest programem, który ma złożoność O (n 1 ), a jego program podwójny ma złożoność O (n 2 ).Następnie mój wniosek brzmi
"abc"ƒ"fed"
, gdzieƒ
jest ocena. W ten sposób"fed"
nie będą oceniane.Generowanie indywidualnego programu
Pseudokod pierwszego komponentu
;(1╖╜ⁿr
:Pseudokod drugiego komponentu
;(1╖╜ⁿ@r
:źródło
Galaretka , 20 bajtów
Częściowo zainspirowany faktycznym rozwiązaniem Leaky Nun .
Wiodące i końcowe znaki nowej linii są znaczące.
Normalna:
Wypróbuj online!
Wejście:
5
Wynik:
Wywrócony:
Wypróbuj online!
Wejście:
5
Wynik:
Podwojony
Wypróbuj online!
Wejście:
5
Wynik:
Podwojone i cofnięte
Wypróbuj online!
Wejście:
5
Wynik:
Wyjaśnienie
Klucz jest tutaj
Ŀ
, co oznacza „wywołuje łącze o indeksie n jako monadę”. Linki są indeksowane od góry do dołu, zaczynając od 1, z wyłączeniem linku głównego (najniższego).Ŀ
jest również modułowy, więc jeśli spróbujesz zadzwonić na numer 7 z 5 linków, faktycznie zadzwonisz na link 2.Łącze wywoływane w tym programie jest zawsze linkiem o indeksie 10 (
⁵
), niezależnie od wersji programu. Jednak, który link ma indeks 10, zależy od wersji.To,
⁵
co pojawia się po każdym,Ŀ
jest tam, więc nie pęka po odwróceniu. Program wyświetli błąd w czasie analizy, jeśli wcześniej nie było numeruĿ
. Posiadanie⁵
po nim jest nie na miejscu nilad, który po prostu idzie prosto do wyjścia.Oryginalna wersja wywołuje link
‘
, który oblicza n + 1.Wersja odwrócona wywołuje łącze
R
, które generuje zakres 1 .. n.Wersja podwójna wywołuje link
2*R
, który oblicza 2 n i generuje zakres 1 .. 2 n .Wersja podwójna i odwrócona wywołuje łącze
²R
, które oblicza n 2 i generuje zakres 1 .. n 2 .źródło
Befunge-98 , 50 bajtów
Normalna
Jest to zdecydowanie najprostszy program z 4 - jedynymi wykonywanymi poleceniami są:
Ten program wykonuje kilka nieistotnych czynności przed naciśnięciem polecenia „skręć w prawo” (
]
) i strzałki. Następnie trafia w 2 polecenia „weź dane”. Ponieważ na wejściu jest tylko 1 liczba i ze względu na to, jak TIO traktuje&
s, program kończy się po 60 sekundach. Jeśli są 2 wejścia (i ponieważ mogę bez dodawania bajtów), IP przechodzi w górę do funkcji „program końcowy”.Wypróbuj online!
Wywrócony
Ten jest trochę bardziej skomplikowany. odpowiednie polecenia są następujące:
co jest równoważne z
Ważna jest tutaj część
:. 1-:!k@
. Jest to przydatne, ponieważ dopóki pchamy prawidłową złożoność na stos przed wykonaniem złożoności w krótszym czasie, możemy uzyskać pożądaną. Zostanie to wykorzystane w pozostałych 2 programach w ten sposób.Wypróbuj online!
Podwojony
A odpowiednie polecenie to:
Ten program przechodzi w 2 pętle. Po pierwsze, podąża tą samą ścieżką, co normalny program, który wypycha 1 i N na stos, ale zamiast zawijać do drugiego
&
, IP przeskakuje komentarz w pętli, która popycha2^N
:Pozostałe bity w linii 4 są pomijane za pomocą
;
sPo wypchnięciu (2 ^ N) na stos, przechodzimy w dół linii do wyżej wspomnianej pętli drukującej. Z powodu pierwszej pętli złożoność czasu wynosi Θ (N + 2 ^ N), ale zmniejsza się do Θ (2 ^ N).
Wypróbuj online!
Podwojone i cofnięte
Odpowiednie polecenia:
Działa to prawie identycznie jak program odwrócony, ale
N^2
nie jest usuwany ze stosu, ponieważ pierwszy wiersz drugiej kopii programu jest dołączany do ostatniego wiersza pierwszego, co oznacza, że polecenie drop ($
) nigdy nie zostanie wykonane , więc wchodzimy w pętlę drukowania zN^2
na górze stosu.Wypróbuj online!
źródło