int sum = 0;
for(int i = 1; i < n; i++) {
for(int j = 1; j < i * i; j++) {
if(j % i == 0) {
for(int k = 0; k < j; k++) {
sum++;
}
}
}
}
Saya tidak mengerti bagaimana ketika j = i, 2i, 3i ... for
loop terakhir berjalan n kali. Saya kira saya hanya tidak mengerti bagaimana kita sampai pada kesimpulan berdasarkan pada if
pernyataan itu.
Sunting: Saya tahu bagaimana menghitung kompleksitas untuk semua loop kecuali untuk mengapa loop terakhir mengeksekusi i kali berdasarkan operator mod ... Saya hanya tidak melihat bagaimana itu saya. Pada dasarnya, mengapa saya tidak bisa naik ke i * i daripada saya?
for (j = i; j < i *i; j += i)
maka Anda tidak memerlukan tes modulus (karenaj
dijamin dapat dibagi olehi
).if
Pernyataan @ChristophBauer sama sekali tidak diabaikan.if
Pernyataan ini berarti kompleksitasnya adalah O (n ^ 4), bukan O (n ^ 5), karena menyebabkan loop terdalam hanya mengeksekusii
waktu alih-alihi*i
waktu untuk setiap iterasi dari loop kedua.k < n^2
Jadi itu O (n ^ 5) tetapi pengetahuan (dengan memahamiif
) menyarankan O (n ^ 4).Jawaban:
Mari beri label loop A, B dan C:
j % i == 0
dievaluasi, yang membutuhkan O (1) waktu.Mengalikan semua ini bersama-sama, kita mendapatkan O ( n × i 2 × (1 + i )) = O ( n × i 3 ). Karena saya adalah rata-rata O ( n ), ini adalah O ( n 4 ).
Bagian yang sulit dari ini adalah mengatakan bahwa
if
kondisinya hanya benar 1 / i saat itu:Bahkan,
j
tidak naik ke atasj < i * i
, bukan hanya sampaij < i
. Tetapi kondisinyaj % i == 0
benar jika dan hanya jikaj
merupakan kelipatani
.Kelipatan dari
i
dalam rentang yangi
,2*i
,3*i
, ...,(i-1) * i
. Adai - 1
ini, sehingga loop C tercapaii - 1
kali meskipun loop Bi * i - 1
berulang kali.sumber
if
kondisi membutuhkan O (1) waktu pada setiap iterasi dari loop B. Ini didominasi oleh loop C di sini, tapi saya menghitungnya di atas sehingga hanya "menunjukkan pekerjaan saya".n
iterasi.n*n
iterasi. Bayangkan kasusnya kapani=n
, laluj=n*n
.n
iterasi karena hanya dieksekusii
berkali-kali, di manai
terikatn
pada kasus terburuk.Dengan demikian, kompleksitas kode adalah O (n × n × n × n).
Saya harap ini membantu Anda mengerti.
sumber
Semua jawaban lain benar, saya hanya ingin mengubah yang berikut. Saya ingin melihat, jika pengurangan eksekusi k-loop dalam cukup untuk mengurangi kompleksitas aktual di bawah ini
O(n⁴).
Jadi saya menulis yang berikut:Setelah melaksanakan ini, menjadi jelas, bahwa kerumitan itu sebenarnya
n⁴
. Baris terakhir dari output terlihat seperti ini:Apa ini menunjukkan, bahwa perbedaan relatif aktual antara aktual
n⁴
dan kompleksitas segmen kode ini adalah faktor asimtotik terhadap nilai sekitar0.124...
(sebenarnya 0,125). Meskipun tidak memberi kami nilai yang tepat, kami dapat menyimpulkan, berikut ini:Kompleksitas waktu adalah di
n⁴/8 ~ f(n)
manaf
fungsi / metode Anda.~
mendefinisikan batas kedua sisi operan adalah sama. Atau:(Saya memilih 363 sebagai batas atas yang dikecualikan, karena
n = 362
nilai terakhir yang kami dapatkan hasilnya masuk akal. Setelah itu, kami melampaui ruang panjang dan nilai relatif menjadi negatif.)Pengguna kaya3 menemukan yang berikut:
sumber
n⁴/8 + o(n⁴)
, tetapi mungkin untuk memberikan ekspresi yang lebih ketatn⁴/8 + O(n³)
dengan huruf O besar.Hapus
if
dan modulo tanpa mengubah kompleksitasInilah metode aslinya:
Jika Anda bingung dengan
if
dan Modulo, Anda hanya bisa refactor mereka pergi, denganj
melompat langsung darii
ke2*i
ke3*i
...:Untuk membuatnya lebih mudah untuk menghitung kompleksitas, Anda dapat memperkenalkan
j2
variabel perantara , sehingga setiap variabel loop bertambah 1 pada setiap iterasi:Anda dapat menggunakan debugging atau old-school
System.out.println
untuk memeriksa bahwai, j, k
triplet selalu sama di setiap metode.Ekspresi bentuk tertutup
Seperti yang disebutkan oleh orang lain, Anda dapat menggunakan fakta bahwa jumlah
n
bilangan bulat pertama sama dengann * (n+1) / 2
(lihat angka segitiga ). Jika Anda menggunakan penyederhanaan ini untuk setiap loop, Anda mendapatkan:Jelas bukan kompleksitas yang sama dengan kode asli tetapi mengembalikan nilai yang sama.
Jika Anda menggunakan istilah pertama di Google, Anda dapat melihat yang
0 0 0 2 11 35 85 175 322 546 870 1320 1925 2717 3731
muncul di "Angka pengadukan dari jenis pertama: s (n + 2, n)." , dengan dua0
s ditambahkan di awal. Ini berarti itusum
adalah angka Stirling dari jenis pertamas(n, n-2)
.sumber
Mari kita lihat dua loop pertama.
Yang pertama sederhana, perulangan dari 1 ke n. Yang kedua lebih menarik. Mulai dari 1 hingga kuadrat. Mari kita lihat beberapa contoh:
Secara total,
i and j loops
gabungan tersebut memiliki1^2 + 2^2 + 3^2
.Ada rumus untuk jumlah n kotak pertama
n * (n+1) * (2n + 1) / 6
, yang kira-kiraO(n^3)
.Anda memiliki yang terakhir
k loop
dari 0 hinggaj
jika dan hanya jikaj % i == 0
. Sejakj
beralih dari 1 kei^2
,j % i == 0
benar untuki
kali. Sejaki loop
iterates berakhirn
, Anda memiliki satu ekstraO(n)
.Jadi, Anda memiliki
O(n^3)
darii and j loops
dan yang lainO(n)
darik loop
untuk totalO(n^4)
sumber
j % i == 0
hanya ketika j adalah 5, 10, 15, 20 dan 25. 5 kali, seperti nilai i. Jika Anda menuliskan angka-angka dari 1 hingga 25 dalam 5 x 5 persegi, hanya kolom ke-5 yang berisi angka-angka yang dapat dibagi 5. Ini berfungsi untuk sejumlah i. Gambarkan sebuah kotak n dengan n menggunakan angka 1 hingga n ^ 2. Kolom ke-n akan berisi angka-angka yang dapat dibagi oleh n. Anda memiliki n baris, sehingga n angka dari 1 hingga n ^ 2 habis dibagi n.i
klik 5, jadij
loop dari 1 hingga 25, Anda tidak dapat memilih nomor acak. Jika loop kedua Anda akan menuju ke nomor tetap, misalnya 24, bukannyai * i
, itu akan menjadi angka konstan dan tidak akan terikatn
, jadi itu akan menjadiO(1)
. Jika Anda berpikir tentangj < i * i
vs.j <= i * i
, itu tidak masalah, karena akan adan
dann-1
operasi, tetapi dalam notasi Big-oh, keduanya berartiO(n)