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++;
}
}
}
}
Ich verstehe nicht, wie wenn j = i, 2i, 3i ... die letzte for
Schleife n-mal läuft. Ich glaube, ich verstehe einfach nicht, wie wir aufgrund der if
Aussage zu diesem Schluss gekommen sind .
Bearbeiten: Ich weiß, wie man die Komplexität für alle Schleifen berechnet, außer warum die letzte Schleife i-mal basierend auf dem Mod-Operator ausgeführt wird ... Ich sehe nur nicht, wie es i ist. Grundsätzlich, warum kann ich nicht zu i * i anstatt zu i gehen?
for (j = i; j < i *i; j += i)
Dann benötigen Sie den Modultest nicht (da erj
garantiert durch teilbar isti
).if
Aussagen werden absolut nicht ignoriert. Dieseif
Anweisung bedeutet, dass die Komplexität O (n ^ 4) anstelle von O (n ^ 5) ist, da die innerste Schleife bei jeder Iteration der zweiten Schleife nuri
Zeiten anstelle voni*i
Zeiten ausführt .k < n^2
Also ist es O (n ^ 5), aber Wissen (durch das Verstehen desif
) legt O (n ^ 4) nahe.Antworten:
Beschriften wir die Schleifen A, B und C:
j % i == 0
wird ausgewertet, was O (1) Zeit in Anspruch nimmt.Wenn wir all dies zusammen multiplizieren, erhalten wir O ( n × i 2 × (1 + i )) = O ( n × i 3 ). Da i im Durchschnitt O ( n ) ist, ist dies O ( n 4 ).
Der schwierige Teil davon ist zu sagen, dass die
if
Bedingung nur 1 / i der Zeit wahr ist :In der Tat
j
geht esj < i * i
nicht nur umj < i
. Aber die Bedingungj % i == 0
ist genau dann wahr, wennj
ein Vielfaches von isti
.Die Multiples von
i
innerhalb des Bereichs sindi
,2*i
,3*i
, ...,(i-1) * i
. Es gibti - 1
davon, so dass Schleife Ci - 1
trotz Iterationszeiten von Schleife Bi * i - 1
mal erreicht wird.quelle
if
Bedingung bei jeder Iteration von Schleife B O (1) Zeit benötigt. Sie wird hier von Schleife C dominiert, aber ich habe sie oben gezählt, damit sie nur "meine Arbeit zeigt".n
Iterationen.n*n
Iterationen. Stellen Sie sich den Falli=n
dann vorj=n*n
.n
Iterationen, da sie nuri
mal ausgeführt wird, woi
sien
im schlimmsten Fall begrenzt ist.Somit ist die Codekomplexität O (n × n × n × n).
Ich hoffe das hilft dir zu verstehen.
quelle
Alle anderen Antworten sind richtig, ich möchte nur Folgendes ändern. Ich wollte sehen, ob die Reduzierung der Ausführungen der inneren k-Schleife ausreicht, um die tatsächliche Komplexität unten zu reduzieren.
O(n⁴).
Also schrieb ich Folgendes:Nachdem dies ausgeführt wurde, wird klar, dass die Komplexität tatsächlich ist
n⁴
. Die letzten Ausgabezeilen sehen folgendermaßen aus:Dies zeigt, dass der tatsächliche relative Unterschied zwischen dem tatsächlichen
n⁴
und der Komplexität dieses Codesegments ein Faktor ist, der asymptotisch gegenüber einem Wert um0.124...
(tatsächlich 0,125) ist. Obwohl es uns nicht den genauen Wert gibt, können wir Folgendes ableiten:Zeitkomplexität ist,
n⁴/8 ~ f(n)
wof
Ihre Funktion / Methode ist.~
Definition der Grenze der beiden Operandenseiten gleich ist. Oder:(Ich habe 363 als ausgeschlossene Obergrenze gewählt, da dies
n = 362
der letzte Wert ist, für den wir ein vernünftiges Ergebnis erhalten. Danach überschreiten wir den langen Raum und der relative Wert wird negativ.)Der Benutzer kaya3 hat Folgendes herausgefunden:
quelle
n⁴/8 + o(n⁴)
, aber es ist trotzdem möglich,n⁴/8 + O(n³)
mit Big O einen strengeren Ausdruck zu geben .Entfernen
if
und modulieren, ohne die Komplexität zu ändernHier ist die ursprüngliche Methode:
Wenn Sie durch das
if
und modulo verwirrt sind , können Sie sie einfach umgestalten,j
indem Sie direkt voni
nach2*i
nach3*i
... springen :Um die Berechnung der Komplexität noch einfacher zu gestalten, können Sie eine Zwischenvariable einführen
j2
, sodass jede Schleifenvariable bei jeder Iteration um 1 erhöht wird:Sie können Debugging oder Old-School verwenden,
System.out.println
um zu überprüfen, ob dasi, j, k
Triplett bei jeder Methode immer gleich ist.Ausdruck in geschlossener Form
Wie von anderen erwähnt, können Sie die Tatsache verwenden, dass die Summe der ersten
n
Ganzzahlen gleich istn * (n+1) / 2
(siehe Dreieckszahlen ). Wenn Sie diese Vereinfachung für jede Schleife verwenden, erhalten Sie:Es ist offensichtlich nicht die gleiche Komplexität wie der ursprüngliche Code, aber es gibt die gleichen Werte zurück.
Wenn Sie die ersten Begriffe googeln, können Sie feststellen, dass
0 0 0 2 11 35 85 175 322 546 870 1320 1925 2717 3731
sie in "Stirling-Zahlen der ersten Art: s (n + 2, n)" erscheinen. , mit zwei0
s am Anfang hinzugefügt. Dies bedeutet, dass diessum
die Stirling-Nummer der ersten Art ists(n, n-2)
.quelle
Werfen wir einen Blick auf die ersten beiden Schleifen.
Der erste ist einfach, er schleift von 1 nach n. Der zweite ist interessanter. Es geht von 1 bis ich im Quadrat. Sehen wir uns einige Beispiele an:
Insgesamt haben die
i and j loops
kombinierten1^2 + 2^2 + 3^2
.Es gibt eine Formel für die Summe der ersten n Quadrate
n * (n+1) * (2n + 1) / 6
, die ungefähr istO(n^3)
.Sie haben eine letzte
k loop
Schleife von 0 bisj
genau dann, wennj % i == 0
. Daj
geht von 1 bisi^2
,j % i == 0
gilti
mal. Da diei loop
Iterationen vorbei sindn
, haben Sie eine zusätzlicheO(n)
.Sie haben also
O(n^3)
ausi and j loops
und ein andererO(n)
ausk loop
für eine Gesamtsumme vonO(n^4)
quelle
j % i == 0
nur, wenn j 5, 10, 15, 20 und 25 ist. 5-mal, wie der Wert von i. Wenn Sie die Zahlen von 1 bis 25 in einem Quadrat von 5 x 5 notieren würden, würde nur die 5. Spalte die durch 5 teilbaren Zahlen enthalten. Dies funktioniert für eine beliebige Anzahl von i. Zeichnen Sie ein Quadrat von n mal n mit den Zahlen 1 bis n ^ 2. Die n-te Spalte enthält die durch n teilbaren Zahlen. Sie haben n Zeilen, also n Zahlen von 1 bis n ^ 2, teilbar durch n.i
Treffer 5, also diej
Schleifen von 1 bis 25, können Sie keine beliebige Zahl wählen. Wenn Ihre 2. Schleife zu einer festen Zahl gehen würde, z. B. 24,i * i
wäre dies eine konstante Zahl und wäre nicht daran gebundenn
, so wäre esO(1)
. Wenn Sie überj < i * i
vs. nachdenkenj <= i * i
, wird das nicht vieln
n-1
O(n)