When do you multiply by the average Big O of nested loop? - algorithm

When do we multiply the Big O of the outer loop by the average Big O of the inner loop?
for (int i = n; i > 0; i /= 2) {
for (int j = 0; j < i; j++) {
//statement
}
}
Answer: O(n)
In this question, the outer loop is O(log n). Since the inner loop executes some number of times based on 'i', the average Big O is taken. This results in a summation of n + n/2 + n/4 + ... = 2n which is then divided to get the average: O(2n / log n).
Hence O(log n) * O(2n / log n) = O(n).
But then why don't we need to take the average for this question?
for (i = 0; i < n; i++) {
for (j = 0; j < i * i ; j++){
}
}
Answer: O(n^3)
The outer loop is O(n). The inner loop is O(n^2). But why?
Doesn't the inner loop execute based on a value of 'i' in the outer loop? So why isn't the average taken like the question above? - resulting in something like O(n^2 / n) for the inner loop.

The complexity of an algorithm is determined by counting how many operations it performs when executed. For a loop which iterates k times, where m is the mean number of operations on each iteration, the total number of operations performed is always total = k * m, simply because the mean is defined to be m = total / k.
It also makes sense to do this in big O notation: if a loop iterates O(k) times, and performs a mean of O(m) operations on each iteration, then the total number of operations is O(k * m).
The problem is that in your second example, you are not calculating the mean correctly. When you say "The inner loop is O(n^2)", this is already the mean; you are considering the number of iterations of the inner loop for one iteration of the outer loop. The total number of iterations is O(n^3), and the number of iterations of the outer loop is n, so the mean is O(n^3 / n) = O(n^2) as expected.
It is more natural to do this calculation the other way around: after observing that the mean is O(n^2), and the outer loop iterates O(n) times, the total is O(n^2 * n) = O(n^3).

Related

Time complexity of dependent nested loops

I was trying to find the time complexity of this nested loop
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
n--;
x++;
}
}
If there wasn't a n-- it would be n*n , O(n2) right?
But what if n reduces every time second loop runs?
What's the time complexity and big O of this nested loop?
If I consider n = 5, x equals 4, the second loop runs 4 time
The time complexity of the code is O(n). n is reduced by half for every iteration of the outer loop.
So we have n/2 + n/4 + n/8 + n/16 + ... + n/2^k = O(n)
where k is the number of iterations of the outer loop (basically i).
Note that the time complexity is independent of x.
If there wasn't a n-- it would be n*n , O(n2) right?
Yes
Another way to see it's O(n): You only enter the inner loop body if j <= n, and since j is positive, n must also be positive. But you decrease n every time, which you can only do O(n) times (where n is the starting value) and still have n positive.

Time Complexity of algorithm with nested if statement and for loops

So im trying to solve this question but me and my friends are a bit confused by it
for (Int64 i = 1; i < Math.Pow(2, n); i = 2*i)
{
if (i <= 4 || i >= Math.Pow(2, n - 2))
{
for (Int64 j = n; j >= 0; j = j - 2)
{
//constant number of C operations
}
}
else
{
for (Int64 j = n; j > 1; j = (Int64) Math.Ceiling((double) j/2))
{
//constant number of C operations
}
}
}
I get that the outer loop is O(n) but I can't get what the inner part is, I'm pretty sure it's just O(n) since the largest of the inner for loops i the top one at O(n) as apposed to the lower one which is O(log n).
Is this the right way in thinking about it? or am i wrong
but I can't get what the inner part is, I'm pretty sure it's just O(n) since the largest of the inner for loops i the top one at O(n) as apposed to the lower one which is O(log n)
The top inner loop is indeed Θ(n). It does not follow that the inner part is Θ(n), at least not in the sense that you should multiply this by the Θ(n) of the outer loop, obtaining an overall Θ(n2). This is because the top loop in the inner part is executed only a constant number of times. The Θ(n) of the top inner loop should be added to that of the outer loop.
The overall complexity of this code is Θ(n log(n)). Specifically, it is Θ(n) Θ(log(n)) (total complexity of executing the bottom inner loop altogether) + Θ(n) + Θ(n) (total complexity of executing the top inner loop altogether).

Finding the complexity of Loops

I'm given this algorithm and I'm told to find the complexity of it big theta.
for (i = 1; i <= n; i++) {
j = n;
while( j >= 1) {
j = j/3;
}
}
I know outer for loop runs n times. The while loop is more tricky though, Is it possibly log n (of base 3). In total making it n*log3n
Is this correct?
There is an outer for loop of size n. It contributes a complexity of a factor of n to the over all complexity.
Let's say inner while loop runs for m times. After i'th iteration, the value of j will be n/(3^i). We will run this till n/(3^i) > 1. Therefore,
=> n/(3^i) = m
=> n = 3^m
=> log(n) = log2(3) * m
=> m = O(log(n))
So, for loop contributes to O(n) and while loop contributes to O(log(n)). Complexity of nested loop becomes O(n log(n)).

Time complexity analysis inconsistency

I have this code :
int fun(int n)
{
int count = 0;
for (int i = n; i > 0; i /= 2)
for (int j = 0; j < i; j++)
count += 1;
return count;
}
The time complexity of this code can be thought of as O(n) because O(n+n/2+n/4+...) = O(n)
By that logic, the time complexity of this snippet can also be argued to be O(n) :
for(i = 1; i < n; i *= 2)
//O(1) statements
Since O(1+2+4+..+n/4+n/2) = O(n). But since the loop runs log(n) times, it can be log(n) too.
Why is the former one not : log(n) times the outer loop * log(n) times the inner loop so, log(n)log(n)
What am I doing wrong ?
The first snippet has the outer loop that executes O(log n) times, and each iteration the inner loop executes O(i) times. If you sum any number of terms of the form n / 2^k, you'll get O(n).
The second piece of code has O(log n) iterations of O(1) operations, and sum of logarithmic amount of constants is still logarithmic.
In the first example, you don't have an O(1) statement inside your loop, as you have for (int j = 0; j < i; j++) count += 1. If in your second example you put the same inner loop of the first example, you are back to the same complexity. The first loop is not O(n*log(n)); this is easy to demonstrate because you can find an upper bound in O(2n) which is equivalent to O(n).
The time complexity of the 2nd one should not be calculated as a series O(1+2+4+..+n/4+n/2) = O(n), because it is not that series.
Notice the first one. It is being calculated as a series because one counts the number of times the inner for loop executes and then add all of them (series) to get the final time complexity.
When i=n inner for loop executes n times
When i=(n/2) inner for loop executes n/2 times
When i=(n/4) inner for loop executes n/4 times
and so on..
But in the second one, there is no series to add. It just comes to a formula (2^x) = n, which evaluates to x = logn.
(2^x) = n this formula can be obtained by noticing that i starts with 1, and when it becomes 2 it is multiplied by 2 until it reaches n.
So one needs to find out how many times 2 needs to be multiplied by 2 to reach n.
Thus the formula (2^x) = n, and then solve for x.

Complexity of a nested geometric sequence

Below code is actually bounded by O(n^2), could anyone please explain why?
for (int i = 1; i < n; i++) {
int j = i;
while (j < n) {
do operation with cost O(j)
j = j * 3;
}
}
It's not that tricky.
Your inner loop's complexity forms a geometric progression with total omplexity O(n).
Without filling the details all the way (this seems like a HW problem), note that the formula for a geometric sequence is
a_0 (q^k - 1) / q - 1, (a_0 = first element, q = multiplication factor, k = num elements).
and your q^k here is O(n).
Your outer loop is O(n).
Since it's a nested loop, and the inner term does not depend on the outer index, you can multiply.
The proof is geometric progression :)
For i = n, the inner loop doesn't execute more than once if i > n/3 (because in next iteration j is >= n).
So for 2n/3 iterations of outer loop the inner loop iterates only once and does O(j) operation. So for 2n/3 iterations the complexity is O(n^2).
To calculate complexity of remaining iterations set n = n/3, now apply steps 1, 2 and 3
Methodically, using Sigma notation, you may do the following:

Resources