Tulis sebuah program (atau fungsi) yang memperlihatkan empat kompleksitas waktu O besar yang umum tergantung pada cara dijalankannya. Dalam bentuk apa pun yang diperlukan dalam bilangan bulat N positif yang Anda anggap kurang dari 31 .
Ketika program dijalankan dalam bentuk aslinya , ia harus memiliki kompleksitas konstan . Yaitu, kompleksitasnya harus Θ (1) atau, dengan kata lain, Θ (1 ^ N) .
Ketika program dibalik dan dijalankan harus memiliki kompleksitas linier . Artinya, kompleksitasnya harus Θ (N) atau, ekuivalen, Θ (N ^ 1) .
(Ini masuk akal karenaN^1
yang1^N
terbalik.)Ketika program ini dua kali lipat , yaitu concatenated untuk dirinya sendiri, dan menjalankannya harus memiliki eksponensial kompleksitas, khususnya 2 N . Artinya, kompleksitasnya harus Θ (2 ^ N) .
(Ini masuk akal karena2
in2^N
adalah double1
in1^N
.)Ketika program digandakan dan dibalik dan dijalankan harus memiliki kompleksitas polinomial , khususnya N 2 . Artinya, kompleksitasnya harus Θ (N ^ 2) .
(Ini masuk akal karenaN^2
yang2^N
terbalik.)
Keempat kasus ini adalah satu-satunya yang perlu Anda tangani.
Perhatikan bahwa untuk ketepatan saya menggunakan notasi theta (Θ) besar alih-alih O besar karena runtime program Anda harus dibatasi baik di atas maupun di bawah oleh kompleksitas yang diperlukan. Kalau tidak, hanya menulis fungsi dalam O (1) akan memenuhi keempat poin. Tidak terlalu penting untuk memahami nuansa di sini. Terutama, jika program Anda melakukan operasi k * f (N) untuk beberapa konstanta k maka kemungkinan dalam Θ (f (N)).
Contoh
Jika program aslinya
ABCDE
maka menjalankannya akan membutuhkan waktu yang konstan. Yaitu, apakah input N adalah 1 atau 2147483647 (2 31 -1) atau nilai apa pun di antaranya, ia harus diakhiri dalam jumlah waktu yang kira-kira sama.
Versi program yang dibalik
EDCBA
harus mengambil waktu linier dalam hal N. Artinya, waktu yang dibutuhkan untuk mengakhiri harus sebanding dengan N. Jadi N = 1 membutuhkan waktu paling sedikit dan N = 2147483647 mengambil paling banyak.
Versi program yang berlipat ganda
ABCDEABCDE
harus mengambil dua-to-the-N waktu dalam hal N. Artinya, waktu yang dibutuhkan untuk mengakhiri harus kira-kira sebanding dengan 2 N . Jadi jika N = 1 berakhir dalam waktu sekitar satu detik, N = 60 akan membutuhkan waktu lebih lama dari umur alam semesta untuk berakhir. (Tidak, kamu tidak perlu mengujinya.)
Versi program yang berlipat dan terbalik
EDCBAEDCBA
harus mengambil waktu kuadrat dalam hal N. Artinya, waktu yang diperlukan untuk mengakhiri harus sebanding dengan N * N. Jadi jika N = 1 berakhir dalam sekitar satu detik, N = 60 akan memakan waktu sekitar satu jam untuk berakhir.
Detail
Anda perlu menunjukkan atau berargumen bahwa program Anda berjalan dalam kompleksitas yang Anda katakan demikian. Memberikan beberapa data waktu adalah ide yang baik tetapi juga mencoba menjelaskan mengapa secara teoritis kerumitannya benar.
Tidak apa-apa jika dalam praktiknya waktu yang diambil program Anda tidak sepenuhnya mewakili kompleksitasnya (atau bahkan deterministik). mis. input N +1 mungkin terkadang berjalan lebih cepat dari N.
Lingkungan tempat Anda menjalankan program tidak masalah. Anda dapat membuat asumsi dasar tentang bagaimana bahasa populer tidak pernah secara sengaja membuang waktu dalam algoritme tetapi, misalnya, jika Anda tahu versi Java Anda mengimplementasikan bubble sort daripada algoritma penyortiran yang lebih cepat , maka Anda harus memperhitungkannya jika Anda melakukan penyortiran .
Untuk semua kompleksitas di sini asumsikan kita berbicara tentang skenario terburuk , bukan yang terbaik atau rata-rata.
Kompleksitas ruang program tidak masalah, hanya kompleksitas waktu.
Program dapat menghasilkan apa saja. Yang penting mereka mengambil bilangan bulat positif N dan memiliki kompleksitas waktu yang tepat.
Komentar dan program multiline diizinkan. (Anda dapat menganggap
\r\n
terbalik\r\n
untuk kompatibilitas Windows.)
Pengingat O Besar
Dari tercepat ke paling lambat itu O(1), O(N), O(N^2), O(2^N)
(urutan 1, 2, 4, 3 di atas).
Istilah yang lebih lambat selalu mendominasi, mis O(2^N + N^2 + N) = O(2^N)
.
O(k*f(N)) = O(f(N))
untuk konstanta k. Jadi O(2) = O(30) = O(1)
dan O(2*N) = O(0.1*N) = O(N)
.
Ingat O(N^2) != O(N^3)
dan O(2^N) != O(3^N)
.
Lembar contekan O yang besar dan rapi.
Mencetak gol
Ini adalah kode golf normal. Program asli terpendek (waktu konstan) dalam byte menang.
sumber
n = input(); for i in xrange(n): pass
memiliki kompleksitas eksponensial, karena dibutuhkan2 ** k
langkah - langkah, di manak = log_2(n)
ukuran inputnya. Anda harus mengklarifikasi apakah ini masalahnya, karena secara dramatis mengubah persyaratan.Jawaban:
Python 3 , 102 byte
Cobalah online!
Ini dari O (1 ^ n), karena inilah yang dilakukan oleh program:
Terbalik:
Cobalah online!
Ini dari O (n ^ 1), karena ini yang dilakukan oleh program:
Dua kali lipat:
Cobalah online!
Ini dari O (2 ^ n), karena inilah yang dilakukan oleh program:
Berganda dan terbalik:
Cobalah online!
Ini dari O (n ^ 2), karena inilah yang dilakukan oleh program:
sumber
input()
?k
apakah input, danl
satu, jadi Anda masih menghitung1**k
, kan? Yang mana yang perluO(log(k))
waktu, terlepas dari kenyataan bahwa Anda dan saya dan semua orang sudah tahu sebelumnya bahwa itu adalah satu?Perl 5,
827371 +1 + (untuk -n flag) = 72 byteSaya yakin saya bisa bermain golf ini (lebih banyak) lebih banyak, tetapi ini adalah waktu tidur, saya telah menghabiskan cukup banyak waktu debugging, dan saya bangga dengan apa yang saya miliki sejauh ini.
Program itu sendiri tidak menggunakan input, dan hanya mengevaluasi string yang dimulai dengan komentar dan kemudian melakukan penggantian string tunggal, jadi ini jelas dalam waktu yang konstan. Ini pada dasarnya setara dengan:
Dua kali lipat:
Bit yang sebenarnya membutuhkan waktu eksponensial adalah eval kedua: ia mengevaluasi perintah
say for(1..2**$_)
, yang mendaftar semua angka dari 1 hingga 2 ^ N, yang jelas membutuhkan waktu eksponensial.Terbalik:
Ini (secara naif) menghitung penjumlahan dari input, yang jelas membutuhkan waktu linier (karena setiap penambahan adalah dalam waktu konstan). Kode yang benar-benar dijalankan setara dengan:
Baris terakhir hanya agar ketika perintah ini diulangi akan memakan waktu kuadratik.
Terbalik dan digandakan:
Ini sekarang mengambil penjumlahan dari penjumlahan input (dan menambahkannya ke penjumlahan input, tetapi apa pun). Karena memang melakukan
N^2
penambahan pesanan , ini membutuhkan waktu kuadratik. Ini pada dasarnya setara dengan:Baris kedua menemukan penjumlahan dari input, melakukan
N
penambahan, sedangkan yang keempat melakukansummation(N)
penambahan, yaituO(N^2)
.sumber
$x.=q;##say...
bukannya$x.=q;#say...
(dengan dua#
bukannya 1). (Itu akan menjelaskan mengapa Anda menghitung 76 byte, bukan 75). Juga, Anda harus menghitung-n
bendera dalam bytecount Anda, karena program Anda tidak akan banyak membantu tanpa itu.eval
dans///
perintahnya. Jika Anda melakukan yangeval
pertama, Anda hanya perlu yang satu#
. Tangkapan yang bagus!#
: produk yang$x=~s/#//;
dibalik;//#/s~=x$
, yang dalam konteks Anda tidak melakukan apa-apa, seperti yang terjadi pada pemimpin#
. (Saya belum mengujinya). Apapun, miliki +1!Sebenarnya , 20 byte
Cobalah online!
Memasukkan:
5
Keluaran:
Terbalik:
Cobalah online!
Keluaran:
Dua kali lipat:
Cobalah online!
Keluaran:
Berganda dan terbalik:
Cobalah online!
Keluaran:
Ide utama
Sebenarnya adalah bahasa berbasis stack.
abc
adalah program yang memiliki kompleksitas O (1 n ), dan gandanya memiliki kompleksitas O (2 n ).def
adalah program yang memiliki kompleksitas O (n 1 ), dan gandanya memiliki kompleksitas O (n 2 ).Lalu, kiriman saya adalah
"abc"ƒ"fed"
, di manaƒ
dievaluasi. Dengan begitu,"fed"
tidak akan dievaluasi.Generasi program individu
Kodesemu dari komponen pertama
;(1╖╜ⁿr
:Kode pseud dari komponen kedua
;(1╖╜ⁿ@r
:sumber
Jelly , 20 byte
Sebagian terinspirasi oleh solusi Sebenarnya Leaky Nun .
Baris baru terkemuka dan tertinggal sangat penting.
Normal:
Cobalah online!
Memasukkan:
5
Keluaran:
Terbalik:
Cobalah online!
Memasukkan:
5
Keluaran:
Dua kali lipat
Cobalah online!
Memasukkan:
5
Keluaran:
Dua kali lipat dan Terbalik
Cobalah online!
Memasukkan:
5
Keluaran:
Penjelasan
Kuncinya di sini adalah
Ŀ
, yang berarti "menyebut tautan di indeks n sebagai monad." Tautan diindeks dari atas ke bawah mulai dari 1, tidak termasuk tautan utama (terbawah).Ŀ
bersifat modular juga, jadi jika Anda mencoba untuk memanggil tautan nomor 7 dari 5 tautan, Anda sebenarnya akan memanggil tautan 2.Tautan yang dipanggil dalam program ini selalu merupakan yang ada di indeks 10 (
⁵
), apa pun versi programnya. Namun, tautan mana yang berada di indeks 10 tergantung pada versinya.Yang
⁵
muncul setelah masingĿ
- masing ada sehingga tidak pecah ketika terbalik. Program akan melakukan kesalahan saat parse-time jika tidak ada nomor sebelumnyaĿ
. Memiliki⁵
after adalah nilad yang tidak pada tempatnya, yang langsung menuju ke output.Versi asli memanggil tautan
‘
, yang menghitung n +1.Versi terbalik memanggil tautan
R
, yang menghasilkan kisaran 1. n.Versi ganda memanggil tautan
2*R
, yang menghitung 2 n dan menghasilkan kisaran 1 .. 2 n .Versi ganda dan terbalik memanggil tautan
²R
, yang menghitung n 2 dan menghasilkan kisaran 1. .. n 2 .sumber
Befunge-98 , 50 byte
Normal
Sejauh ini, ini adalah program paling sederhana dari 4 - satu-satunya perintah yang dieksekusi adalah sebagai berikut:
Program ini melakukan beberapa hal yang tidak penting sebelum menekan perintah "belok kanan" (
]
) dan panah. Kemudian muncul 2 "take input" perintah. Karena hanya ada 1 angka dalam input dan karena cara TIO memperlakukan&
, program keluar setelah 60 detik. Jika ada 2 input (dan karena saya bisa tanpa menambahkan byte), IP akan naik ke fungsi "end program".Cobalah online!
Terbalik
Yang ini sedikit lebih rumit. perintah yang relevan adalah sebagai berikut:
yang setara dengan
Bagian penting di sini adalah
:. 1-:!k@
bit. Ini berguna karena selama kita mendorong kompleksitas yang benar ke tumpukan sebelum mengeksekusi dalam kompleksitas waktu yang lebih rendah, kita bisa mendapatkan yang diinginkan. Ini akan digunakan dalam 2 program yang tersisa dengan cara ini.Cobalah online!
Dua kali lipat
Dan perintah yang relevan adalah:
Program ini masuk ke dalam 2 loop. Pertama, ia mengikuti jalur yang sama dengan program normal, yang mendorong 1 dan N ke stack, tetapi alih-alih membungkus ke yang kedua
&
, IP melompati komentar ke dalam loop yang mendorong2^N
:Bit lain pada baris 4 dilewati menggunakan
;
sSetelah (2 ^ N) didorong ke tumpukan, kami memindahkan garis ke dalam lingkaran pencetakan yang disebutkan di atas. Karena loop pertama, kompleksitas waktu adalah Θ (N + 2 ^ N), tetapi itu berkurang menjadi Θ (2 ^ N).
Cobalah online!
Dua kali lipat dan Terbalik
Perintah yang relevan:
Fungsi ini hampir identik dengan program terbalik, tetapi
N^2
tidak muncul dari tumpukan, karena baris pertama dari salinan kedua program ditambahkan ke baris terakhir yang pertama, yang berarti bahwa perintah drop ($
) tidak pernah dijalankan , jadi kita masuk ke lingkaran pencetakan denganN^2
di bagian atas tumpukan.Cobalah online!
sumber