Analyzing the time complexity of this function - time-complexity

Assuming do_something is O(1), how do I calculate the time complexity of this function?
function run(n) {
for(var i = 1; i <= n; i++) {
var counter = 1;
while(counter <= n) {
for (var j = counter; j >= 1; j--) {
do_something();
}
counter = counter * 2;
}
}
}
I'm assuming the initial for loop means the that the complexity will be n and the inner while loop means log(n). Is this true?
How do I calculate the complexity of everything?
Thanks.

It's not trivial to calculate the complexity of everything because there are functions (e. g. collatz conjecture) where no exact analysis is known. In such a case you can do an empirical analysis where you guess which run time class would match best.
Related to your sample:
The outer for loop is called n times
The while loop is called log(n) times
The inner for loop is called counter times where counter grows 2^m. But counter is recalculated log(n) times
That means the inner exponential for loop (2^m) is called m=log(n) times.
So you have 2^(log n) = n log(2) = n
You can also do it vice versa. The inner exponential function is called log times. Means log(2^m) -> (2^n = 2^m) -> m = n.
You can also simply create a sum of 2^m from m=0 to m=log(n) which is 2n-1 -> O(n).
Then you have to multiply linear time of outer for loop with linear time of while loop (incl. inner for loop). So you have O(n*n) = O(n²) time.

The exact amount of steps can be calculated.
The outer loop runs n times
The while and inner-most loop is run counter times for each of the values of counter, these are 1, 2, 4, 8, ..., 2^(bitLength(n)-1)
which sums to 2^bitLength(n) - 1
where bitLength(n) = trunc(ln(n)/ln(2))+1
Multiplying these two, yields the exact amount of steps:
n * (2^bitLength(n) - 1)
The approximate complexity is O(n2), because O(2^bitLength(n) - 1) = O(n)

Related

Time complexity of these two while loops

x = 1;
while(x<n)
{
x = x + n / 10;
m = n*n
y = n;
while(m>y)
{
m=m-100;
y=y+20;
}
}
The way I solved it: we are adding to x 1/10 of n every time, so no matter how big n will be, the number of repitation we are doing is always 10.
The inner loop is from n to n^2, and each variable in it is increasing linearly, so the inner loop should be O(n)
and because the outer loop is O(1), we get O(n) for all of the function.
but the optional answers for the question are: O(n^2), O(n^3), O(n^4), O(nlogn)
What am I missing? thanks.
You are correct that the outer loop runs a constant number of times (10), but your reasoning about the inner loop isn't all the way there. You say that there is a "linear increase" with each iteration of the inner loop , and if that were the case you would be correct that the whole function runs in O(n), but it's not. Try and figure it out from here, but if you're still stuck:
The inner loop has to make up the difference between n^2 and n in terms of the difference between m and y. That difference between m and y is reduced by a constant amount with each iteration: 120, not a linear amount. Therefore the inner loop runs (n^2 - n)/120 times. Multiplying the number of times the outer loop runs by the times the inner loop runs, we get:
O(10) * O((n^2 - n)/120)
= O(1) * O(n^2)
= O(n^2)

What is the time complexity of below func?

What is the running time complexity of fun()?
int fun(int n)
{
int count = 0;
for (int i = n; i > 0; i =i-2)
for (int j = 2; j < i; j=j*j)
for (int k=j; k>0; k=k/2)
count += 1;
return count;
}
is it O(n * lglgn * lglglgn)?
----
Edit:
j = loglog(i) times, big iterative value of j can be almost n(for example n=17,max(j)=16)
k= log(j), since the max value of j is at most n. then the max iterative times can be log(n)
so we can say that the big O of this question is O(n* lglgn * lgn)
Since the value of j and k depends on the previous iterative value (i, j), maybe there is better tight answer to this question.
We need to count this carefully, because the number of iterations of each inner loop depends in a non-trivial way on the outer loop's variable. Simply averaging for each loop and multiplying the results together will not give the right answer.
The outer loop runs O(n) times, because i counts from n down to 0 in constant steps.
The middle loop's values of j are 2, then 2*2 = 4, then 4*4 = 16, and on the m'th iteration, j = 2^2^m. The last iteration will be when 2^2^m >= i, in which case m >= log log i. So this runs O(log log i) times.
The innermost loop runs O(log j) times, because on the m'th iteration, k = j / 2^m. The last iteration will be when k <= 1, in which case m >= log j. So this runs O(log j) times.
However, it is not correct to multiply these together to get O(n * log log n * log log log n) - because i is not n on every iteration, and j is not log log n on every iteration. This gives an upper bound, but not a tight one. To calculate the true time complexity, you will need to write it as a double-summation, and simplify it algebraically.
As a simpler example to think about, consider the following code:
for(i = 1; i < n; i *= 2) {
for(j = 0; j < i; j += 1) {
// do something
}
}
The outer loop runs O(log n) times, and the inner loop runs O(i) times, but the overall complexity is actually O(n). To see this, count how many times // do something is reached; the first time the outer loop iterates it'll be 1, then it'll be 2, then 4, then 8, and so on up to n. This is a geometric progression with a sum <= 2n, giving a total number of steps which is O(n).
Note that if we naively multiply the two loops' complexities we get O(n log n) instead, which is an upper bound, but not a tight one.
Using Big O notation:
With the first outer loop we get O(N/2). You have a loop of N items and you are reducing it by 2 everytime, though you get a total of N/2 loops.
With the outter loop we get O(Log(I)).
With the most inner loop we have O(Log(J)), because you are dividing by 2 your iterator on every loop.
If we multiply the three complexities because they are nested:
O(N/2)*O(Log(I)) + O(Log(j)) ~ O(N/2*Log(I)*Log(J)) ~ O(N/2*Log^2(N)) ~ O(N*Log^2(N)).
We get a linearithmic complexity: O(N*Log^2(N))

what is the time complexity of a nested for loop that iterates n - 1 - i?

So if I have a loop like this?
int x, y, z;
for(int i = 0; i < n - 1; i++) {
for(int j = 0; j < n - 1 - i; j++){
x = 1;
y = 2;
z = 3;
}
}
so we start with the x, y, z definition so we have 4 operations there,
int i = 0 occurs once, i < n - 1 and i++ iterate n - 1 times, int j = 0, iterates n - 1 times and j < n - 1 - i and j++ iterates (n - 1) * (n - 1 - i) and xyz = 1 would iterate (n - 1) * (n - 1 - i) as well. So if I were to simplify this, would the above code run at O(n^2)?
so we start with the x, y, z definition so we have 4 operations there
This is not necessary, we need only count critical operations (i.e. in this case how often the loop body executes).
So if I were to simplify this, would the above code run at O(n²)?
A function T(n) is in O(g(n)) if T(n) <= c*g(n) (under the assumption n >= n0) for some constants c > 0, n0 > 0.
So for your code, the loop body is executed n - i times for every i, of which there are n. So we have:
Which is indeed true for c = 1/2, n0 = 1. Therefore T(n) ∈ O(n²).
You are correct that the complexity is O(n^2). There is more than one way to approach the question of why.
The formal way is to count the number of iterations of the inner loop, which will be n-1 the first time, then n-2, then n-3, ... all the way down to 1, giving a total of n*(n-1)/2 iterations, which is O(n^2).
An informal way is to say the outer loop runs O(n) times, and "on average", i is roughly n/2, so the inner loop runs on average about (n - n/2) = n/2 times, which is also O(n). So the total number of iterations is O(n) * O(n) = O(n^2).
With both of these techniques, it's not enough to just say that the loop body iterates O(n^2) times - we also need to check the complexity of the inner loop body. In this code, the body of the inner loop just does a few assignments, so it has a complexity of O(1). This means the overall complexity of the code is O(n^2) * O(1) = O(n^2). If instead the inner loop body did e.g. a binary search over an array of length n, then that would be O(log n) and the overall complexity of the code would be O(n^2 log n), for example.
Yes, you are right. Time complexity of this program will be O(n^2) at its worst case.

What is worst case time complexity for given function?

Void func(int n){
Int k=n;
Int i=0;
for(;i<n;i++){
while(k>1){
k>>=1;
}
}
What is worst case time complexity of the function? explain the solution also.
In the first iteration of the outer loop, the inner loop runs log2(n) times. This is because k is repeatedly divided by 2 (right shift by 1), so its value decreases exponentially.
However for all other iterations of the outer loop, the value of k is still less than 1, so the inner loop does not run.
Therefore the time complexity is given by T(n) = Ө(n - 1) + Ө(log2(n)) = Ө(n).

Compute Time Complexity

I got skunked in computing the time complexity in the inner loop.
Lets consider the following case.
Case 1:
for(int i = 0; i <= n; i++) - O(n)
{
for(int j = 0; j <= i; j++) - O(?);
{
//Some thing goes here
}
}
Here the inner loop got executed every time up to value i.
So, can I tell like, the complexity for the inner loop is some O(i),
and the overall complexity is O(N) * O(I); ie: O(N*I)
Could some one explain in some brief manner, so i can able to understand the computing.
Thanks.
The overall time complexity is O(n²) (in fact, it’s even Θ(n²)).
The inner loop has complexity O(i). However, n is related to i, so simply saying that the whole thing has complexity O(ni) is wrong. The body of the inner loop will run 0 + 1 + 2 + ⋯ + n = (n² + n) / 2 = Θ(n²) times.
Before i go over what you asked for i will explain a simple example.
We caliculate the time complexity based on how many times the innermost loop is executed
consider this case:
for(i=0;i<n;i++){
for(j=0;j<n;j++){
....
}
}
here the outer loop is executed n times and in every iteration the inner loop is executed n times.
1st iteration - n
2st iteration - n
3st iteration - n
.
.
.
nth iteration -n
so the inner loop is executed n*n times.so it is O(n^2).
Now we caliculate for the case what you asked for
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++){
//Some thing goes here
}
}
Here the Outer loop is executed for n times. and in every i'th iteration the inner loop is executed i times.
1st iteration - 1
2nd iteration - 2
3rd iteration - 3
.
.
.
nth iteration -n
so when we caliculate it would be
1+2+3+.....+n = n(n+1)/2
which is basically O(n^2). :)