How is this loop's time complexity O(n^2)? - c

How is this loop's time complexity O(n^2)?
for (int i = n; i > 0; i -= c)
{
for (int j = i+1; j <=n; j += c)
{
// some O(1) expressions
}
}
Can anyone explain?

Assumption
n > 0
c > 0
First loop
The first loop start with i=n and at each step, it substracts c from i. On one hand, if c is big, then the first loop will be iterated only a few times. (Try with n=50, c=20, you will see). On the other hand, if c is small (let say c=1), then it will iterate n times.
Second loop
The second loop is the same reasoning. If c is big, then it will be iterated only a few times, if c is small, many times and at the worst case n times.
Combined / Big O
Big O notation gives you the upper bound for time complexity of an algorithm. In your case, first and second loop upper bound combined, it gives you a O(n*n)=O(n^2).

Related

time complexity of nested loops - always just a multiplication of each of them seperated?

When looking at this code for example :
for (int i = 1; i < n; i*=2)
for (int j = 0; j < i; j +=2)
{
// some contstant time operations
}
Is it as simple as saying that because the outer loop is log and and inner loop is n , that combined the result is big(O) of nlogn ?
Here is the analysis of the example in the question. For simplicity I will neglect the increment of 2 in the inner loop and will consider it as 1, because in terms of complexity it does not matter - the inner loop is linear in i and the constant factor of 2 does not matter.
So we can notice, that the outer loop is producing is of values which are powers of 2 capped by n, that is:
1, 2, 4, 8, ... , 2^(log2 n)
these numbers are also the numbers that the "constant time operation" in the inner loop is running for each i.
So all we have to do is to sum up the above series. It is easy to see that these are geometric series:
2^0 + 2^1 + 2^2 + ... + 2^(log2 n)
and it has a well known solution:
(from Wiki )
We have a=1, r=2, and... well n_from_the_image =log n. We have a same name for different variables here, so it is a bit of a problem.
Now let's substitute and get that the sum equals
(1-2^((log2 n) + 1) / (1 - 2) = (1 - 2*n) / (1-2) = 2n-1
Which is a linear O(n) complexity.
Generally, we take the O time complexity to be the number of times the innermost loop is executed (and here we assume the innermost loop consists of statements of O(1) time complexity).
Consider your example. The first loop executes O(log N) times, and the second innermost loop executes O(N) times. If something O(N) is being executed O(log N) times, then yes, the final time complexity is just them multiplied: O(N log N).
Generally, this holds true with most nested loops: you can assume their big-O time complexity to be the time complexity of each loop, multiplied.
However, there are exceptions to this rule when you can consider the break statement. If the loop has the possibility of breaking out early, the time complexity will be different.
Take a look at this example I just came up with:
for(int i = 1; i <= n; ++i) {
int x = i;
while(true) {
x = x/2;
if(x == 0) break;
}
}
Well, the innermost loop is O(infinity), so can we say that the total time complexity is O(N) * O(infinity) = O(infinity)? No. In this case we know the innermost loop will always break in O(log N), giving a total O(N log N) time complexity.

Determining the time complexity of this code?

I think the time complexity of this code will be O(n^2) but I am not sure so if someone can explain what will be the time complexity of this code it would be really helpful
int func2()
{
int i, j, k = 0;
scanf("%d", &n);
for (i = 1; i < n; i++)
{
i -= 1;
i *= 2;
k = k + i;
for (j = 1; j < n; j++);
}
}
It looks like an infinite loop to me, so the time complexity is O(infinity).
On the first iteration of the outer loop, i -= 1 will set i to 0. Multiplying by 2 leaves it still 0.
The loop iteration i++ will then increment i to 1, and the next iteration will repeat the above computations.
I am a beginner on time complexity but these are my views:-
The outer for loop is in the condition of an infinite loop as on the first iteration of the outer loop, execution starts with i=1.
On executing i -= 1 it will set i=0.
Executing i*=2, the value of i remains the same as 0.
On going in the increment phase, i is incremented and i=1.
So the same process occurs.
Thus the value of i remains the same causing it to run indefinitely.
Now, coming forward inside the outer for loop is a nested for (in the variable j) loop that is followed by a semicolon. This causes it to have a time complexity of O(1).
So the resultant overall time complexity can be expected to be O(infinity).
First, 'n' not declared here and input value is being assigned to it.
Second, technically, this code is an infinite loop (done ridiculously hard way) and for non-terminating, forever-running algorithms the time-complexity is 'Undefined' as by the principles of Algorithm Analysis, time-complexity is only computed for algorithms that perform a task with certainity to terminate.
In case if this would have been a terminating loop, time complexity of this function is O(n^2) would have been quadratic in nature due to nesting of for(;;) inside of another for(;;) with enclosed statements of O(1) - linear time complexity. The higher order complexity ( O(n^2) ) supersedes.

Writing down the worst-case running time O(n) of this given code?

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.

Calculating Time Complexity for nested loops

Got this question on a test that I've been stuck on for a few days regarding Big O time complexity analysis:
Below is the C code:
if ( A > B ) {
for ( i=0; i<n^2/100; i++ ){ //1
for ( j=n^2; j>i; j-- ){ //2
A += B;}}
}
else {
for ( i=0; i<2n; i++ ){ //3
for ( j=3n; j>i; j-- ){ //4
A += B;}}
}
My first instinct was that this algorithm would have a big O of O(n2) with the nested for loops and such but it wasn't a multiple choice answer. Tried to count each loop iteration manually but having trouble accounting for the changing i in each inside loop (2 and 4). Also having trouble trying to write it as a summation.
Consider the first case where A > B. The inner loop executes a number of iterations equal to n^2 - i for each value of i iterated over by the outer loop. Consider n = 2 and i = 1. n^2 = 4 and the inner loop iterates over j = 4, j = 3, j = 2, three iterations, consistent with our finding.
The total number of iterations of the inner loop is therefore the sum of all n^2 - i where i varies from 0 to floor(n^2/100) - 1. Let us define k := floor(n^2/100) - 1. Then this sum is equal to kn^2 - k(k+1)/2. Substituting the expression for which k stands we recover [floor(n^2/100) - 1]n^2 - [floor(n^2/100) - 1][floor(n^2/100)]/2. This is no greater than (n^2/100 - 1)n^2 - (n^2/100 - 1)(n^2/100)/2. We may multiply through to get n^4/100 - n^2 - n^4/20000 + n^2/200 = n^4(1/100 - 1/20000) - n^2(1 - 1/200). From this we can see that the time complexity of the first case is O(n^4). Indeed, it is also Omega(n^4) and Theta(n^4).
In the case where A <= B, the analysis is similar. It is easy to show that the time complexity of the second case is O(n^2), Omega(n^2) and thus Theta(n^2).
Therefore, we may confidently say that:
The worst-case time complexity is O(n^4);
The best-case time complexity is Omega(n^2);
Each of these bounds may actually be given as Theta bounds instead.

Confused with Big O Notation

So I get that the first for loop runs O(n) times, then inside that it runs 3 times, then 3 times again. How do I express this at big O notation though? Then do the 2 print statements matter? How do I add them to my big-o expression? Thanks, really confused and appreciate any help.
for (int x = 0; x < n; x++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
printf("%d", arr[x]);
}
printf("\n");
}
}
O(n) is linear time, so any k * O(n) where k is a constant (like in your example) is also linear time and is just expressed as O(n). Your example has O(n) time complexity.
Big O notation are always defined as a function of input size - n. Big O gives the upper limit of total time taken to run that module. Because your inner "for" loops are always run 3*3 =9 times irrespective of the input size of n - there are still considered as constant time in Big O calculations
Time Complexity = O(n+9+constantTimeToPrint) = O(n)
The two inner loops are constant, so it's still O(n). constant factors don't matter, the runtime varies only with the input size.

Resources