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++;
}
}
}
}
Je ne comprends pas comment quand j = i, 2i, 3i ... la dernière for
boucle s'exécute n fois. Je suppose que je ne comprends tout simplement pas comment nous sommes arrivés à cette conclusion sur la base de la if
déclaration.
Edit: je sais comment calculer la complexité de toutes les boucles, sauf pourquoi la dernière boucle exécute i fois en fonction de l'opérateur de mod ... Je ne vois tout simplement pas comment c'est i. Fondamentalement, pourquoi j% i ne peut-il pas aller jusqu'à i * i plutôt que i?
for (j = i; j < i *i; j += i)
alors vous n'avez pas besoin du test de module (car ilj
est garanti d'être divisible pari
).if
déclarations @ChristophBauer ne sont absolument pas ignorées. Cetteif
instruction signifie que la complexité est O (n ^ 4) au lieu de O (n ^ 5), car elle oblige la boucle la plus interne à exécuter uniquement desi
temps au lieu dei*i
fois pour chaque itération de la deuxième boucle.k < n^2
partie. C'est donc O (n ^ 5) mais la connaissance (en comprenant leif
) suggère O (n ^ 4).Réponses:
Étiquetons les boucles A, B et C:
j % i == 0
est évalué, ce qui prend du temps O (1).En multipliant tout cela ensemble, nous obtenons O ( n × i 2 × (1 + i )) = O ( n × i 3 ). Puisque i est en moyenne O ( n ), c'est O ( n 4 ).
La partie délicate de cela est de dire que la
if
condition n'est vraie que 1 / i du temps:En fait,
j
ne monte pasj < i * i
, pas seulementj < i
. Mais la conditionj % i == 0
est vraie si et seulement sij
est un multiple dei
.Les multiples de l'
i
intérieur de la gamme sonti
,2*i
,3*i
, ...,(i-1) * i
. Il y en ai - 1
, donc la boucle C est atteintei - 1
fois malgré lesi * i - 1
temps d' itération de la boucle B.la source
if
condition prend du temps O (1) à chaque itération de la boucle B. Elle est dominée par la boucle C ici, mais je l'ai comptée ci-dessus donc c'est juste "montrer mon travail".n
itérations.n*n
itérations. Imaginez le cas quandi=n
, alorsj=n*n
.n
itérations car elle n'est exécutée que desi
fois, où ellei
est limitéen
dans le pire des cas.Ainsi, la complexité du code est O (n × n × n × n).
J'espère que cela vous aide à comprendre.
la source
Toutes les autres réponses sont correctes, je veux juste modifier ce qui suit. Je voulais voir si la réduction des exécutions de la boucle k interne était suffisante pour réduire la complexité réelle ci-dessous.
O(n⁴).
J'ai donc écrit ce qui suit:Après avoir exécuté cela, il devient évident que la complexité est en fait
n⁴
. Les dernières lignes de sortie ressemblent à ceci:Ce que cela montre, c'est que la différence relative réelle entre le réel
n⁴
et la complexité de ce segment de code est un facteur asymptotique vers une valeur autour0.124...
(en fait 0,125). Bien qu'il ne nous donne pas la valeur exacte, nous pouvons en déduire ce qui suit:La complexité du temps est
n⁴/8 ~ f(n)
où sef
trouve votre fonction / méthode.~
définition de la limite des deux côtés de l'opérande est égale. Ou:(J'ai choisi 363 comme borne supérieure exclue, car
n = 362
c'est la dernière valeur pour laquelle nous obtenons un résultat sensible. Après cela, nous dépassons l'espace long et la valeur relative devient négative.)L'utilisateur kaya3 a compris ce qui suit:
la source
n⁴/8 + o(n⁴)
, mais il est tout de même possible de donner une expression plus stricten⁴/8 + O(n³)
avec un grand O.Supprimer
if
et modulo sans changer la complexitéVoici la méthode originale:
Si vous êtes confus par le
if
et modulo, vous pouvez simplement les refactoriser, enj
sautant directement dei
à2*i
à3*i
...:Pour faciliter encore plus le calcul de la complexité, vous pouvez introduire une
j2
variable intermédiaire , de sorte que chaque variable de boucle est incrémentée de 1 à chaque itération:Vous pouvez utiliser le débogage ou la vieille école
System.out.println
afin de vérifier que lei, j, k
triplet est toujours le même dans chaque méthode.Expression de forme fermée
Comme mentionné par d'autres, vous pouvez utiliser le fait que la somme des premiers
n
entiers est égale àn * (n+1) / 2
(voir les nombres triangulaires ). Si vous utilisez cette simplification pour chaque boucle, vous obtenez:Ce n'est évidemment pas la même complexité que le code d'origine mais il renvoie les mêmes valeurs.
Si vous recherchez sur Google les premiers termes, vous pouvez remarquer qu'ils
0 0 0 2 11 35 85 175 322 546 870 1320 1925 2717 3731
apparaissent dans "Numéros de Stirling du premier type: s (n + 2, n)". , avec deux0
s ajoutés au début. Cela signifie quesum
c'est le nombre de Stirling du premier types(n, n-2)
.la source
Jetons un coup d'œil aux deux premières boucles.
Le premier est simple, il est en boucle de 1 à n. Le second est plus intéressant. Cela va de 1 à i au carré. Voyons quelques exemples:
Au total, les
i and j loops
combinés ont1^2 + 2^2 + 3^2
.Il existe une formule pour la somme des n premiers carrés
n * (n+1) * (2n + 1) / 6
, qui est approximativementO(n^3)
.Vous avez une dernière
k loop
boucle de 0 àj
if et seulement ifj % i == 0
. Depuisj
va de 1 ài^2
,j % i == 0
est vrai pour lesi
temps. Puisque l'i loop
itération est terminéen
, vous en avez un de plusO(n)
.Vous avez donc
O(n^3)
dei and j loops
et un autre àO(n)
partirk loop
pour un grand total deO(n^4)
la source
j % i == 0
seulement lorsque j vaut 5, 10, 15, 20 et 25. 5 fois, comme la valeur de i. Si vous notiez les nombres de 1 à 25 dans un carré de 5 x 5, seule la 5e colonne contiendrait les nombres divisibles par 5. Cela fonctionne pour n'importe quel nombre de i. Tracez un carré de n par n en utilisant les nombres 1 à n ^ 2. La nième colonne contiendra les nombres divisibles par n. Vous avez n lignes, donc n nombres de 1 à n ^ 2 divisibles par n.i
frappe 5, donc lesj
boucles de 1 à 25, vous ne pouvez pas choisir un nombre arbitraire. Si votre 2ème boucle devait aller à un nombre fixe, par exemple 24, au lieu dei * i
, ce serait un nombre constant et ne serait pas lién
, alors ce serait le casO(1)
. Si vous pensez àj < i * i
vsj <= i * i
, cela n'aura pas beaucoup d'importance, car il y auran
etn-1
opérations, mais dans la notation Big-oh, les deux moyensO(n)