I have been asked to determine the big-O time complexity of this code:
function(int n) {
for (int i = 0; i < n; i++) {
for (int j = i; j < i *
Mathematical form for total time complexity of this question in a worst case is as follow:
So complexity is
O(n^5)
.
Edit: In above answer I don't attention to if
performance.
We can change your code as follow:
function(int n) {
for (int i = 0; i < n; i++) {
for (int j = i; j < i * i; j+=i) {
for (int k = 0; k < j; k++) {
printf("*");
}
}
}
}
So,as templatetypedef mentioned, it is evident that total runtime is O(n^4)
.
So the O time complexity is the product of the maximum individual iteration count for each loop nested in terms of an arbitrary variable n of interest.
Here you have
function (int n) // as in O(n)
{
for(int i=0;i<n;i++) // n
{
for(int j=i;j<i*i;j++) // n ^ 2
{
if(j%i==0) // w/e
{
for(int k=0;k<j;k++) // n ^ 2
{
printf("*");
}
}
}
}
}
n * n^2 * n^2 = n^5
Interestingly you will find that the number of "*" printed is not n^5 what ever, this is a consequence if the if condition, you will find for a given positive int n the count of * will be < n ^ 5 and potentially > n ^ 4 .
By using the product of the maximum number of iterations for each loop we can quickly get the ceiling of the end behavior of a function as n increases arbitrarily.
One way to analyze code like this is to start from the innermost loop and work outward. That loop is
for (int k=0; k<j; k++)
{
printf("*");
}
This has time complexity Θ(j). So now let's look at the next loop:
for (int j=i; j<i*i; j++)
{
if (j%i==0)
{
// do Theta(j) work
}
}
This one is interesting. This loop will run Θ(i2) times. Most iterations will do O(1) work, but every ith iteration will do Θ(j) work. We can therefore separate the work done here into two pieces: the baseline Θ(i2) work done just from looping a lot, plus the extra work done from intermittently doing Θ(j) work.
That part where we do Θ(j) work happens every i iterations. This means that work done will be roughly
i + 2i + 3i + 4i + ... + i2
= i(1 + 2 + 3 + 4 + ... + i)
= iΘ(i2)
= Θ(i3)
So overall, this loop does Θ(i3) work. This dominates the Θ(i2) work from the outer loop, so the total work done here is Θ(i3).
Finally, we can work our way to the outermost loop, which looks like this:
for (int i=0; i<n; i++)
{
// Do Theta(i^3) work
}
The work done here is roughly
03 + 13 + 23 + 33 + ... + (n-1)3
= Θ(n4)
So overall, the total work done here is Θ(n4). This is a tighter bound than the O(n5) given in the problem statement, so either
Remember that big-O notation is used to give an upper bound on the runtime of a piece of code, so saying that the runtime is O(n5) if the runtime is actually Θ(n4) isn't wrong; it's just not tight. It wouldn't be wrong to say it's O(n100) either, though this isn't a very useful bound.
One way we can check this is to write a program that just counts up how many times the innermost loop runs and to compare that against n4 for various values of n. I wrote a program that does just that. It's shown below:
#include <iostream>
#include <cstdint>
#include <cmath>
using namespace std;
uint64_t countWork(int n) {
uint64_t result = 0;
for (int i = 0; i < n; i++) {
for (int j = 1; j < i * i; j++) {
if (j % i == 0) {
for (int k = 0; k < j; k++) {
result++;
}
}
}
}
return result;
}
int main() {
for (int n = 100; n <= 1000; n += 100) {
cout << "Ratio of work to n^4 when n = "
<< n << " is " << countWork(n) / pow(double(n), 4.0)
<< endl;
}
}
Here's the output:
Ratio of work to n^4 when n = 100 is 0.120871
Ratio of work to n^4 when n = 200 is 0.122926
Ratio of work to n^4 when n = 300 is 0.123615
Ratio of work to n^4 when n = 400 is 0.123961
Ratio of work to n^4 when n = 500 is 0.124168
Ratio of work to n^4 when n = 600 is 0.124307
Ratio of work to n^4 when n = 700 is 0.124406
Ratio of work to n^4 when n = 800 is 0.12448
Ratio of work to n^4 when n = 900 is 0.124537
Ratio of work to n^4 when n = 1000 is 0.124584
From this it looks like the runtime is roughly approaching 0.125n4, which is roughly n4 / 8. That actually makes sense - the hidden constant factor from the innermost loop is 1/2 (since 1 + 2 + 3 + ... + i = i(i+1)/2) and the hidden constant factor from the outermost loop is 1/4 (since 13 + 23 + ... + n3 = n2(n + 1)2 / 4). In other words, the theory really closely matches the practice!