Time complexity of the code containing condition - algorithm

foo(int n)
{
int s=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=i*i;j++)
if(j%i==0)
for(k=1;k<=j;k++)
s++;
}
What is the time complexity of the above code?
I am getting it as O(n^5) but it is not correct.

The complexity is O(n^4).
Innermost loop will be executed i times for each i. (i multiples of i within 0..i*i)
It will be like the inner loop will run for
j = 0 1 2...i i+1 ...2*i ....3*i .... 4*i .... 5*i... i*i
x x x x x x
\------/\--------/\-------/ \------/
These x denotes the execution of the innermost for loop with complexity j. Rest of the time this is not touched and just the test is done and it fails.
So now check the thing, these \-----/ has i*j (j = 1,2,3...i) looping and i checks.
And now we do i times precisely.
So total work = i*(1+1+1+...1) + i*(1+2+3+..i)
= i*i+ i*i*(i+1)/2 ~ i^3
With the outer loop it will be n^4.
Now what is the meaning of it. The whole work can be divided in like this
O(i*j+i)
^^^ ^
| The other cases when it simply skips
The innermost loop executed
Now if we iterate over j then it will have complexity O(n^3).
With added external loop it will be O(n^4).

Your function computes 4-dimensional pyramidal numbers (A001296). The number of increments to s can be computed using this formula:
a(n) = n*(1+n)*(2+n)*(1+3*n)/24
Therefore, the complexity of your function is O(n4).
The reason it is not O(n5) is that if (j%i == 0) proceeds with the "payload" loop only for multiples of i, of which we have exactly i among all js in the range from 1 to i2, inclusive.
Hence, we add one for the outermost loop, one for the loop in the middle, and two for the innermost loop, because it iterates up to i2, for the total of 4.
Why only one for middle (j) ? It runs up to i2 right?
Perhaps it would be easier to see if we rewrite the code to exclude the condition:
int s=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
for(int k=1;k<=i*j;k++)
s++;
return s;
This code produces the same number of "payload loop" iterations, but rather than "filtering out" the iterations that skip the inner loop it removes them from consideration by computing the terminal value of k in the innermost loop as i*j.

Related

Time complexity of two separate nested while loops

I just started my data structures course and I'm having troubles trying to figure out the time complexity in the following code:
{
int j, y;
for(j = n; j >= 1; j--)
{
y = 1;
while (y < j)
y *= 2;
while (y > 2)
y = sqrt(y);
}
The outer 'for' loop is running n times in every run of the code, and the first 'while' loop runs about log2(j) if I'm not mistaken.
I'm not sure about the second 'while' loop and how to determine the overall time complexity of the code.
My initial thoughts were to determine which 'while' loop would "cost" more in each iteration of the 'for' loop, consider only the higher of the two and sum it up but obviously it didn't lead me to an answer.
Would appreciate any help, especially in what is the the process and overall approach in trying to compute the complexity in codes such as this one.
You are right that the first while loop has time complexity O(log(j)). The second while loop repeatedly executes square root on y until it's less than 2.
Since y is approximately j (it's between j and 2j), the question is: how often can you perform a square root on j until you get a number less than or equal to 2? But equivalently you could ask: how often can you square 2 until you get a number larger than or equal to j? Or as an equation:
(((2^2)^...)^2 >= j // k repeated squares
<=> 2^(2^k) >= j
<=> k >= log(log(j))
So the second while loop has time complexity O(log(log(j)). That's negligible compared to O(log(j)). Now since j <= n and the loop is itereated n times, we get the overall complexity O(n log(n)).

Time complexity of nested for-loop with two independent variables

I am trying to calculate the time complexity of this function:
int fun1(A, k){ //A is an array, k is an integer
n = length(A); //length of array
for j:= 1 to k{
for i:= j to n{
if A[i] < A[j-1]{
x:= A[j-1];
A[j-1]:= A[i];
A[i]:= x
}
}
}
return A[k-1]}
We iterate k times in the outer loop, but how to calculate number of iterations of inner loop, and then the time complexity of entire algorithm?
Since the work inside the double loop is constant and assuming that k<=n then the complexity can be written as
Edit: I forgot the constant but it doesn't matter as it will disappear inside the big Oh notation

Big O for this triple nested loop?

What's the big O of this?
for (int i = 1; i < n; i++) {
for (int j = 1; j < (i*i); j++) {
if (j % i == 0) {
for (int k = 0; k < j; k++) {
// Simple computation
}
}
}
}
Can't really figure it out. Inclined to say O(n^4 log(n)) but feel like i'm wrong here.
This is quite a confusing analysis, so let's break it down bit by bit to make sense of the calculations:
The outermost loop runs for n-1 iterations (since 1 ≤ i < n).
The next loop inside it makes (i² - 1) iterations for each index i of the outer loop (since 1 ≤ j < i²).
In total, this means the number of iterations for these two loops is equal to calculating the sum of (i²-1) for each 1 ≤ i < n. This is similar to computing the sum of the first n squares, and is order of magnitude of O(n³).
Note the modulo operator % takes constant time (O(1)) to compute, therefore checking the condition if (j % i == 0) for all iterations of these two loops will not affect the O(n³) runtime.
Now let's talk about the inner loop inside the conditional.
We are interested in seeing how many times (and for which values of j) this if condition evaluates to true, since this would dictate how many iterations the innermost loop will run.
Practically speaking, (j % i) will never equal 0 if j < i, so the second loop could actually be shortened to start from i rather than from 1, however this will not impact the Big-O upper bound of the algorithm.
Notice that for a given number i, (j % i == 0) if and only if i is a divisor of j. Since our range is (1 ≤ j < i²), there will be a total of (i-1) values of j for which this will be true, for any given i. If this is confusing, consider this example:
Let's assume i = 4. Then our index j would iterate through all values 1,..,15=i²,
and (j%i == 0) would be true for j = 4, 8, 12 - exactly (i - 1) values.
The innermost loop would therefore make a total of (12 + 8 + 4 = 24) iterations. Thus for a general index i, we would look for the sum: i + 2i + 3i + ... + (i-1)i to indicate the number of iterations the innermost loop would make.
And this could be generalized by calculating the sum of this arithmetic progression. The first value is i and the last value is (i-1)i, which results in a sum of (i³ - i²)/2 iterations of the k loop for every value of i. In turn, the sum of this for all values of i could be computed by calculating the sum of cubes and the sum of squares - for a total runtime of O(n⁴) iterations of the innermost loop (the k loop) for all values of i.
Thus in total, the runtime of this algorithm would be the total of both runtimes we calculated above. We checked the if statement O(n³) times and the innermost loop ran for O(n⁴), so assuming // Simple computation runs in constant time, our total runtime would come down to:
O(n³) + O(n⁴)*O(1) = O(n⁴)
Let us assume that i = 2.Then j can be [1,2,3].The "k" loop will run for j = 2 only.
Similarly for i=3,j can be[1,2,3,4,5,6,7,8].hence, k can run for j = 3,6. You can see a pattern here that for any value of i, the 'k' loop will run (i-1) times.The length of loops will be [i,2*i,3*i,....i*i].
Hence the time complexity of k loop is
=i+(2*i)+(3*i)+ ..... +(i*i)
=(i^2)(i+1)/2
Hence the final complexity will be
= (n^3)(n+3)/2

Is a loop that is running a constant number of times considered Big - Oh(1)?

From a popular definition ,a loop or recursion that runs a constant number of times is also considered as O(1).
For example the following loop is O(1)
// Here c is a constant
for (int i = 1; i <= c; i++) {
// some O(1) expressions
}
Time Complexity of a loop is considered as O(n) if the loop variables is incremented / decremented by a constant amount.
For example following functions have O(n) time complexity.
// Here c is a positive integer constant
for (int i = 1; i <= n; i += c) {
// some O(1) expressions
}
I got a little confused with the following example here lets take c = 5 and according to the O(1) definition the below code becomes - O(1)
for(int i = 0; i < 5 ; i++){
cout<<"Hello<<endl";
}
Function 1:
for(int i = 0; i < len(array); i+=2){
if(key == array[i])
cout<<"Element found";
}
Function 2:
for(int i =0;i < len(array) ; i++){
if(key == array[i])
cout<<"Element found";
}
But when we compare the above 2 examples will they both become O(n) or first function is O(1) from definition.What exaclty does a loop running constant number of times means?
Assuming that len(array) is the b we're talking about [*], both your functions are O(n).
Function 2 will execute the if n times (once for each element of the array), making it obviously O(n).
Function 1, on the other hand, will execute the if n/2 times (once for every other element in the array), leading to a run time of O(n*1/2), and since constant factors (1/2 in this case) are usually omitted in O notation, you'll again end up with O(n).
[*] For the sake of completeness, if your array were of a fixed size, ie. len(array) were a constant, than both functions would be O(1).
"Loop running a costant number of times" means the loop runs a number of times that is limited from above by a constant, i.e. a given number that is indipendent from the input of your program.
Both in function 1 and 2 (unless the lenghts of the arrays are fixed or you can prove they'll never be grater than a specific constant, indipendently of the input) the if will be execute a number of time that depends on the size of the input so the time complexity can't be O(1).
"Time Complexity of a loop is considered as O(n) if the loop variables is incremented / decremented by a constant amount" is a misleading definition

Assistance required for calculating algorithmic complexity - CSc fundamentals

Hi I have two algorithms that need their complexity worked out, i've had a try myself at first; O(N^2) & O(N^3) Here they are:
Treat Y as though it's declared 'y=int[N][N]' and B as though 'B=int[N][N]'....
int x(int [] [] y)
{
int z = 0
for (int i =0; i<y.length; i++)
z = z + y[i].length;
return z;
}
int A (int [] [] B)
{
int c =0
for ( int i =0; i<B.length; i++)
for (int j =0; j<B[i].length; j++)
C = C + B[i] [j];
return C;
}
Thanks alot :)
To caclulate the algorithmic complexity, you need to tally up the number of operations performed in the algorithm (the big-O notation is concerned about worst case scenario)
In the first case, you have a loop that is performed N times (y.length==N). Inside the loop you have one operation (executed on each iteration). This is linear in the number of inputs, so O(x)=N.
Note: calculating y[i].length is a constant length operation.
In the second case, you have the outer loop that is performed N times (just like in the first case), and in each iteration another loop if the same length (N==B[i].length) is executed. Inside the inner loop you have one operation (executed on each iteration of the inner loop). This is O(N*N)==O(N^2) overall.
Note: calculating b[i][j] is a constant length operation
Note: remember that for big-O, only the fastest-growing term matters, so additive constants can be ignored (e.g. the initialization of the return value and the return instruction are both operations, but are constants and not executed in a loop; the term depending on N grows faster than constant)

Resources