Time complexity of a triple-nested loop
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
for(int k=j+1; k<n; k++)
I want to know the right solution of time complexity.
A formal solution to determine the order of growth of your algorithm:
First guess: three loops depending on n, so it should be O(n³)
If you try to compute the exact complexity you have to compute it for the inner an multiply it with the outer loop.
inner loop takes O(n-k)
middle loop takes O(n-j + n-j-1 + ... + n-j-n) = O((n-j) ⋅ (n-j+1) / 2) = O((n-j)²)
outer loop takes O((n-1)² + (n-2)² + ... + (n-n+1)²) = O(n³)
Sure this is not exact, but in terms of big-O it is exact enought.
Related
I have been given the following code:
void sort(int a[], int n)
{
for(int i = 0; i < n - 1; i++)
for(int j = 0; j < n - i - 1; j++)
if(a[j] > a[j+1])
swap(a + j, a + j + 1);
}
I have to calculate the worst-case running time O(n) of this code.
n is 20, so I was thinking, is O(n) = 20 - 1, or is it O(n)= n-1?
Any time you see a double-nested for loop, your first reaction should be :likely O(N²).
But let's prove it.
Start with the outer loop. It will iterate n-1 times. As n gets really large, the -1 part is negligible. So the outer loop iterates pretty close to n iterations.
When i==0, the inner loop will iterate n-2 times. But again, there's not much difference between n and n-2 in terms of scale. So let's just say it iterates n times.
When i==n-2, the inner loop will iterate exactly once.
Hence, the inner loop iterates an average of n/2 times.
Hence, if(a[j] > a[j+1]) is evaluated approximately n * n/2 times. Or n²/2 times. And for Big-O notation, we only care about the largest polynomial and none of the factors in front of it. Hence, O(N²) is the running time. Best, worst, and average.
I'm filling a lower triangular matrix like this:
for (i = 0; i < size; i++) {
for (j = 0; j <= i; j++)
l[i][j] = j + 1;
}
And I want to calculate the order of the code in Big O notation but I'm really bad. If it was a regular matrix it would be O(n²) but in this case I'm not sure if it's O(nlog(n)) or something like that.
Typically (but not always) one loop nested in another will cause O(N²).
Think about it, the inner loop is executed i times, for each value of j. The outer loop is executed size times.
This comes out to be 1/2 of N^2, which is still O(N^2)
I'm wondering what is the time-complexity of the inner for-loop, is it sqrt(n) or log(n)?
void foo(int n)
{
for (int i=0; i<n*n; ++i)
for (int j=1; j*j<n; j*=2)
printf("Hello there!\n");
}
j in inner for loop will take values 1,2,4,...2^t
Also according to constraint given,
2^2t = n
So, t = (1/2)logn
Therefore the inner loop should have Time Complexity O(log(n))
I think the inner for-loop has complexity O(sqrt(n)). To make it O(log(n)), the inner for loop should be something like this:
EDIT
It should be O(log(n)).
This is the function:
void f(int n)
{
for(int i=0; i<n; ++i)
for(int j=0; j<i; ++j)
for(int k=i*j; k>0; k/=2)
printf("~");
}
In my opinion, the calculation of the time complexity would end up to be something like this:
log((n-1)(n-2))+log((n-1)(n-3))+...+log(n-1)+log((n-2)(n-3))+...+log(n-2)+...log(2)
So, I get a time complexity of nlog(n!) (because loga+logb=log(a*b) and because n-1,n-2,n-3,... each appears n-1 times in total.
However, the correct answer is n^2*logn, and I have no idea where my mistake is. Could anyone here help?
Thanks a lot!
log(n!) can be approximated as (n+1/2)log(n) - n + constant (see https://math.stackexchange.com/questions/138194/approximating-log-of-factorial)
So the complexity is n*n*log(n) as expected.
Simpler: compute the complexity loop by loop independently and multiply them.
First 2 outer loops: trivial: n each, which makes n^2
Inner loop: has a log(n**2) complexity which is the same as log(n)
So n^2log(n) is the correct answer.
The Complexity is O(N*N*LOG_2(N^2)).
The first and the second loop both have O(N) and the last loop in k has logarithmic grow.
LOG_2(N^2) = 2*LOG_2(N) and
O(N*M)=O(N)*O(M).
O(constant)=1.
So for the grow of the last loop you can write also O(LOG_2(N^2))=O(LOG(N)).
What would be the time complexity of this following block of code
void function(int n).
My attempt was that the outermost loop would run n/2 times and the inner two would run 2^q times. Then I equated 2^q with n and got q as 1/2(log n) with base 2. Multiplying the time complexities I get my value as O(nlog(n)) while the answer is O(nlog^2(n)).
void function(int n) {
int count = 0;
for (int i=n/2; i<=n; i++)
for (int j=1; j<=n; j = 2 * j)
for (int k=1; k<=n; k = k * 2)
count++;
}
Time to apply the golden rule of understanding loop nests:
When in doubt, work inside out!
Let’s start with the original loop nest:
for (int i=n/2; i<=n; i++)
for (int j=1; j<=n; j = 2 * j)
for (int k=1; k<=n; k = k * 2)
count++;
That inner loop will run Θ(log n) times, since after m iterations of the loop we see that k = 2m and we stop when k ≥ n = 2lg n. So let’s replace that inner loop with this simpler expression:
for (int i=n/2; i<=n; i++)
for (int j=1; j<=n; j = 2 * j)
do Theta(log n) work;
Now, look at the innermost remaining loop. With exactly the same reasoning as before we see that this loop runs Θ(log n) times as well. Since we do Θ(log n) iterations that each do Θ(log n) work, we see that this loop can be replaced with this simpler one:
for (int i=n/2; i<=n; i++)
do Theta(log^2 n) work;
And here that outer loop runs Θ(n) times, so the overall runtime is Θ(n log2 n).
I think that, based on what you said in your question, you had the right insights but just forgot to multiply in two copies of the log term, one for each of the two inner loops.
In your code there are 3 nested loops.
First loop runs n/2 times which is almost equivalent to n while calculating complexity.
Second loop runs logn times.
Third loop runs logn times.
So, finally the time complexity will be O( n * logn * logn ) == O(nlog^2n).
Now, one may wonder how the run time complexity of the two inner loops is logn. This can be generalized as follows:
Since we are multiplying by 2 in each iteration, we need value of q such that:
n = 2 ^ q.
Taking log base 2 on both sides,
log2 n = log2 (2^q)
log2 n = q log2(2)
log2 n = q * 1 [ since, log2(2) is 1 ]
So, q is equal to logn.
So, overall time complexity is: O(n*log^2n).
First loop takes: n/2
Second loop: log(n)
Third loop: log(n)
Notice that because the step of the inner loops is multiplied by two, their respective counters grow exponentially, reaching n in a log(n), in terms of time complexity.
Then, also notice that constants like 1/2 can safely be ignored in that case, which results in O(n * log(n) *log(n)), thus:
O(nlog2n)