Could someone explain the time complexity for these code snippets? - algorithm

I am practicing time complexity and some of them if a bit too complicated for me.
I would really appreciate of someone could explain these for me.
A) The time complexity is O(n). How is that?
for (int i = N; i > 0; i = i/2) {
for (int j = i+i; j > 0; j--) {
doSomething(i, j);
}
}
B) The time complexity is O(n logn). How is that?
for (int i = N+N; i > 0; i--) {
for (int j = N; j > 0; j = j/2) {
doSomething(i, j);
}
}

I suppose we must assume that the execution of doSomething takes constant time, independent of the values it gets as arguments.
Algorithm A:
On the first iteration of the outer loop, the inner loop iterates 2𝑁 times. Every next iteration of the outer loop, the number of iterations of the inner loop is halved. So we get this series:
      2𝑁 + 𝑁 + 𝑁/2 + 𝑁/4 + 𝑁/8 + ... + 2
Given that this series is finite, but has the pattern of 1/2 + 1/4 + 1/8 + 1/16 + ..., we can conclude that this is less than 4𝑁, and so it is O(𝑁).
Algorithm B:
Here the number of iterations of the inner loop does not depend on the value of 𝑖, so it is always the same: each time it performs log2𝑁 iterations (since 𝑗 is halved each iteration). As the outer loop iterates 2𝑁 times, doSomething is called 2𝑁log2𝑁, which is O(𝑁log𝑁)

problem A
Here the first loop will execute log2(n)+1 times, and the second loop will execute i+i times. So what will the value of i in every second loop.
for n, it will be like
n + n/2 + n/4 + n/8 + n/16 + .......
summation of this will be the answer.
as we know
a + ar + ar^2 + ar^3 + ar^4 .... + ar^m = (1-a^(m+1))/(1-a)
here a = n, r = 1/2 and m = log2(n)+1
n + n/2 + n/4 + n/8 + ... n/(2^(m)) =2n−n/2^m = 2n-1;
so the complexity is O(2n-1) = O(n)
problem B
here the first loop will execute n times. And for every first loop execution, the second loop will be executed log2(n)+1 time.
for (int j = n; j > 0; j = j/2)
for example n = 10 ,
value of j will be 10, 5, 2, 1 ,0. For 10 it will execute 4 times or log2(10)+1 times .
so for every first loop it will execute log2(n)+1 times. so the complexity is
O(n(log2(n)+1)) = O (nlog(n))

Related

What is the asymtotic complexity of the following code

I have some doubts about the complexity of the following code
The outer loop is going to execute for O(N) times
I have doubts about the inner loop whether it is going to execute for O(1) or O(n)
for (int i=0; i<n; i++)
for (int j=i; j< i; j+=i)
{
print(“*”);
}
}
As someone pointed out, as the code stands the inner loop will execute 0 times, so I'm assuming you meant:
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j+=i)
{
print(“*”);
}
}
In that case, the number of executions of the inner loop will be N, N/2, N/3, N/4, ... in the subsequent executions of the outer loop. So the total time will be N + N/2 + N/3 + ... = N * (1 + 1/2 + 1/3 + ...). Now, we can see that (1 + 1/2 + 1/3 + 1/4 + ...) <= (1 + 1/2 + 1/4 + 1/4 + 1/8 + 1/8 + 1/8 + 1/8 + ...). This second expression requires twice as many terms for each additional 1/2 (for example you need twice as many 1/8 as 1/4 to make a 1/2) so it will be O(logN). So the total complexity is O(N*logN).
The inner is O(i), which increases everytime, so the global complexity would be:
Number of times the inner loop is executed: 1+2+3+...+n, that is:
Therefore O(n^2)
Because j is initialized to i in the inner loop, that loop never executes as the condition requires j be less than i. Therefore, the complexity is O(n): all this does is increment i in the outer loop and verify during each iteration of the outer loop body that i is not less than i.

Time Complexity - While loop divided by 2 with for loop nested

I am stuck on a review question for my upcoming midterms, and any help is greatly appreciated.
Please see function below:
void george(int n) {
int m = n; //c1 - 1 step
while (m > 1) //c2 - log(n) steps
{
for (int i = 1; i < m; i++) //c3 - log(n)*<Stuck here>
int S = 1; //c4 - log(n)*<Stuck here>
m = m / 2; //c5 - (1)log(n) steps
}
}
I am stuck on the inner for loop since i is incrementing and m is being divided by 2 after every iteration.
If m = 100:
1st iteration m = 100: loop would run 100, i iterates 100 times + 1 for last check
2nd iteration m = 50: loop would run 50 times, i iterates 50 times + 1 for last check
..... and so on
Would this also be considered log(n) since m is being divided by 2?
External loop executes log(n) times
Internal loop executes n + n/2 + n/4 +..+ 1 ~ 2*n times (geometric progression sum)
Overall time is O(n + log(n)) = O(n)
Note - if we replace i < m with i < n in the inner loop, we will obtain O(n*log(n)) complexity, because in this case we have n + n + n +.. + n operations for inner loops, where number of summands is log(n)

Time complexity of nested for loop with inner iteration variable dependent on the outer one

This is the loop structure :
for (int i = 1 ; i < n ; i++) {
for (int j = 0 ; j < n ; j += i) {
// do stuff
}
}
My guess was O(nlogn) as it clearly cannot be O(n^2) since the increment in j is increasing and it clearly cannot be O(n sqrt(n)) since the increment is not that high. But I have no idea how to prove it formally.
Each time complexity of the inner loop is based on the value of i is n/i. Hence, total time would be n + n/2 + n/3 + ... + n/n = n(1+1/2+1/3+...+1/n).
As we know 1+1/2+1/3+...+1/n is a harmonic sereis and asymptotically is log(n). Hence, the algorithm is run in O(nlog(n)).

Time complexity of following code with explanation?

What is the time complexity of this algorithm, and why?
int count = 0;
for (int i = N; i > 0; i /= 2) {
for (int j = 0; j < i; j++) {
count += 1;
}
}
The correct answer is O(n), but I am getting O(nlogn). Can anyone tell me why it's O(n)?
On the first iteration, the inner loop executes N times, and then N/2 times, and then N/4 times, and so on. This can be expressed as an infinite sum:
N + N/2 + N/4 + N/8 + N/16 + N/32 + ...
If you factor out the N from each term, you get:
N * (1 + 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + ...)
The infinite sequence in parentheses converges on the value 2 (more info on Wikipedia). Therefore, the number of operations can be simplified to:
N * 2
In terms of Big-O, the asymptotic value is within:
O(N)
You can check this by observing that the relationship in the output between N and count is linear: Ideone Demo

Asymptotic analysis of three interdependent nested for loops

The code fragment I am to analyse is below:
int sum = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < i * i; j++)
for (int k = 0; k < j; k++)
sum++;
I know that the first loop is O(n) but that's about as far as I've gotten. I think that the second loop may be O(n^2) but the more I think about it the less sense it makes. Any guidance would be much appreciated.
The first loop executes n times. Each time, the value i grows. For each such i, the second loop executes i*i times. That means the second loop executes 1*1 + 2*2 + 3*3 + ... + n*n times.
This is a summation of squares, and the formula for this is well-known. Hence we have the second loop executing (n(1 + n)(1 + 2 n))/6 times.
Thus, we know that in total there will be (n(1 + n)(1 + 2 n))/6 values of j, and that for each of these the third loop will execute 1 + 2 + ... + j = j(j+1)/2 times. Actually calculating how many times the third loop executes in total would be very difficult. Luckily, all you really need is a least upper bound for the order of the function.
You know that for each of the (n(1 + n)(1 + 2 n))/6 values of j, the third loop will execute less than n(n+1)/2 times. Therefore you can say that the operation sum++ will execute less than [(n(1 + n)(1 + 2 n))/6] * [n(n+1)/2] times. After some quick mental math, that amounts to a polynomial of maximal degree 5, therefore your program is O(n^5).
int sum = 0;
for (int i = 0; i < n; i++) // Let's call this N
for (int j = 0; j < i * i; j++) // Let's call this M
for (int k = 0; k < j; k++) // Let's call this K
sum++;
N is the number of steps of the entire program, M is the number of steps the two inner loops do and lastly K is the number of steps the last loop does.
It is easy to see that K = j, it takes j steps to do.
Then M = Sum(j=0,i^2,K) = Sum(j=0, i^2, j)
(First param is the iterator, second is the upper bound and last param is what we are adding)
This is actually now a sum of n numbers to i*i. Which means we can apply the formula ((n+1)*n)/2
M = Sum(j=0,i^2,j) = ((i^2+1)*(i^2))/2 = (i^4 + i^2)/2
N = Sum(i=0, n, M) = 1/2 * ( Sum(i=0, n, (i^4)) + Sum(i=0, n, (i^2)) )
These are both well known formulas and after a little playing you get:
N = (n^5)/10 + (n^4)/4 + (n^3)/3 + (n^2)/4 + n/15
This should be the exact number of steps the loop takes, but if you are interested in the O notation you can note that n^5 is the strongest growing part so the solution is O(n^5)
If you proceed methodically using Sigma Notation, you'll end up with the following result:
Try to count how many times the inner loop is executed:
The middle loop runs
0*0 times when i == 0
1*1 times when i == 1
2*2 times when i == 2
...
n*n = n^2 times when i == n.
So it is O(n^2).

Resources