Time in Big O notation for if(N^2%N==0) - algorithm

I wanted to understand how to calculate time complexity on if statements.
I got this problem:
sum = 0;
for(i=0;i<n;i++)
{
for(j=1;j<i*i;j++)
{
if(j%i==0)
{
for(k=0;k<j;k++)
{
sum++;
}
}
}
}
Now, I understand that for lines (1) and (2) I have n^3 in total, and according to my professor the total time is n^4, I also see that the if statement is testing to check when the remainder of n^2/n is 0, and the for loop in line (4) in my opinion should be n^2, but I don't know how to calculate it in order for lines (3) through (4) have O(n) in total. Any help is welcome. Thanks in advance.

Let's compute sum by rewriting the program and observing some math facts:
Phase 1:
for (i = 0; i < n; i++) {
for (j = 0; j < i*i; j += i) {
sum += j;
}
}
Phase 2 (use arithmetic progression):
for (i = 0; i < n; i++) {
sum += i*i * (i + 1) / 2;
}
Phase 3:
Sum of cubes is a polynomial 4th degree
So, sum = O(n^4). The original program achieves that by adding 1, so it needs O(n^4) additions.

There are 6 lines of actual code here. (You had them all on one line which was very hard to read. John Odom fixed that.)
1) Runs in O(1)
2) Runs in O(n), total is O(n)
3) Runs in O(n^2), total is O(n^3)
4) Runs in O(1), this filters the incoming from O(n^3) to O(n^2)
Edit: I missed the fact that this loop went to n^2 instead of n.
5) Runs in O(n) but this n is the square of the original n, thus it's really O(n^2), total is O(n^4)
6) Runs O(1), total is O(n^4)
Thus the total time is O(n^4)
Note, however:
for(j=1;j<i*i;j++)
{
if(j%i==0)
This would be much better rewritten as
for(j=i;j<i*i;j+=i)
(hopefully I got the syntax right, it's been ages since I've done C.)

Related

Time complexity of an algorithm - embedded loop

I'm trying to solve this algorithm but I'm not sure
here is the code(trying to get the complexity)
For (i =0, i<N, i++) {
For (j=0, j<i/2, j++) {
S.O.P (“”);
}
}
the S.O.P stands for the instructions given to the CPU.
I don't know what S.O.P. stands for, but for the sake of the question, I'll suppose it takes a fixed amount of time - O(1).
Therefore, the only thing left is defining the time the for loops take to run.
for (i =0, i<N, i++) { // n times
For (j=0, j<i/2, j++) { // for each time, this runs n/2 times
S.O.P (“”); // fixed time O(1)
}
}
Given that, we can calculate:
T(n) = {sum for i from 0 to n} i/2 = (1/2)*(n*(n-1)/2)
T(n) = (n*(n - 1)/4) * O(1) = O(n^2/4) = O(n^2)
So the final time complexity would be O(n^2) (O of n squared).

Time Complexity of series of algorithms

I have some doubts about the time complexities of these algorithms:
These are all the possible options for these algorithms
Algorithm 1
int i=0, j=0, sum = 0;
while i*i < n {
while j*j < n {
sum = sum + i * j;
j = j+2;
}
i = i+5;
}
//I don't really know what this one might be, but my poor logic suggests O(sqrt(n))
Algorithm 2
sum = 0;
for (i=0; i<=n; i++){
j = n;
while j>i {
sum = sum + j - i;
j = j – 1;
}
}
//While I know this algorithm has some nested loops, I don't know if the actual answer is O(n^2)
Algorithm 3
for (int i=0; i<=n; i++)
for (int j=0; j<=n; j++){
k = 0;
while k<n {
c = c+ 1;
k = K + 100;
}
}
//I believe this one has a time complexity of O(n^3) since it has 3 nested loops
Algorithm 4
Algorithm int f(int n) {
if n==0 or n == 1
return n
else
return f(n-2)+f(n-1)
//I know for a fact this algorithm is O(2^n) since it is the poor implementation of fibonacci
I think I have an idea of what the answers might be but I would like to get a second opinion on them. Thanks in advance.
Okay so this is what I think, Answers in bold
Algorithm 1
I think this is the most interesting algorithm. Let's build it up from a simple case
Let's temporarily assume it was just 2 nested loops that just checked for i,j being <n and not the the squares of those values. Now the fact that i and j get incremented by 5 and 2 respectively is inconsequential. And the complexity would have just been O(n2).
Now let's factor in the fact that the check is in fact i*i < n and j * j < n. This means that effective value ofyour iterators is their square and not just their absolute value. If it had been just one loop the complexity would have been O(sqrt(n)). But since we have 2 nested loops the complexity become O(sqrt(n) * sqrt(n)) which becomes O(n)
Algorithm 2
Your reasoning is right. It is O(n2)
Algorithm 3
Your reasoning is right. It is O(n3)
Algorithm 4
I don't think this is a fibonacci implementation but your time complexity guess is correct. Why I don't think this is a fibonacci is because this algorithm takes in a large number and works in reverse. You could send in something like 10 which isn't even a fibonacci number.
A nice way to think of this is as a binary tree. Every node, in your case every call to the fn that is not 1 or 0 spawns 2 children. Each call minimally removes 1 from the initial value sent in, say n. Therefore there would be n levels. The maximum number of nodes in a binary tree of depth n is 2n - 1. Therefore O(2n) is right

Is my understanding of big-O correct for these Java functions incorrect?

My approach (might be incorrect) is formulaic. If there is a loop then (n+1) if there is a nested loop (n^2) if a statement then O(1). If division then log(n).
Here are some example and my reasoning to solving, not sure at all if this approach is problematic or if any of them are correct. I need help with this.
Example1:
i = n; // I think O(1) because it's a statment
while (i > 1) // I think O(n) because it's a loop
i = i/4; // O(n) because it's in a loop and log_4(n) b/c division
// I think Overall if we combine the O(n) from earlier and the log_4(n)
// Therefore, I think overall O(nlog(n))
Example2:
for (i = 1; i < n; i = i + i) // I think this is O(n+1) thus, O(n)
System.out.println("Hello World"); // O(n) because it's in a loop
// Therefore, overall I think O(n)
Example3:
for (i = 0; i < n; i = i + 1) // I think O(n+1), thus O(n)
for (j = 1; j < n; j++) // I think O(n^2) because in a nested loop
System.out.println("Hello Universe!"); // O(n^2) because in a nested
// Therefore, overall I think O(n^2)
Example4:
for (i = 1; i < (n * n + 3 * n + 17) / 4; i = i + 1) // O((20+n^3)/4) thus, O(n^3)
System.out.println("Hello Again!'); // O(n) because it's in a loop
// Therefore, overall I think O(n^3) because largest Big-O in the code
Thank you
Example1: Your result is wrong. Because the loop happens log_4(n) times and also the division takes O(1) (division by 4 just needs a bitwise shift). Thus the overall time is only O(log(n))
Example2: It's wrong too. In each iteration you duplicate the loop variable. So the loop happens O(log(n)) times. The print command takes O(1) and total time is O(log(n)).
Example3: Your answer is correct. Because you have two nested O(n) loops. Note that this loop is different from two previous examples.
Example4: I think you made a writing mistake. Does ((n * n + 3 * n + 17) / 4) equal O((20+n^3)/4)??? It is O(n^2). Thus, according to my previous explanations, the overall time is O(n^2).

how i can find the time complexity of the above code

for(i=0; i<n; i++) // time complexity n+1
{
k=1; // time complexity n
while(k<=n) // time complexity n*(n+1)
{
for(j=0; j<k; j++) // time complexity ??
printf("the sum of %d and %d is: %d\n",j,k,j+k); time complexity ??
k++;
}
What is the time complexity of the above code? I stuck in the second (for) and i don't know how to find the time complexity because j is less than k and not less than n.
I always having problems related to time complexity, do you guys got some good article on it?
especially about the step count and loops.
From the question :
because j is less than k and not less than n.
This is just plain wrong, and I guess that's the assumption that got you stuck. We know what values k can take. In your code, it ranges from 1 to n (included). Thus, if j is less than k, it is also less than n.
From the comments :
i know the the only input is n but in the second for depends on k an not in n .
If a variable depends on anything, it's on the input. j depends on k that itself depends on n, which means j depends on n.
However, this is not enough to deduce the complexity. In the end, what you need to know is how many times printf is called.
The outer for loop is executed n times no matter what. We can factor this out.
The number of executions of the inner for loop depends on k, which is modified within the while loop. We know k takes every value from 1 to n exactly once. That means the inner for loop will first be executed once, then twice, then three times and so on, up until n times.
Thus, discarding the outer for loop, printf is called 1+2+3+...+n times. That sum is very well known and easy to calculate : 1+2+3+...+n = n*(n+1)/2 = (n^2 + n)/2.
Finally, the total number of calls to printf is n * (n^2 + n)/2 = n^3/2 + n^2/2 = O(n^3). That's your time complexity.
A final note about this kind of codes. Once you see the same patterns a few times, you quickly start to recognize the kind of complexity involved. Then, when you see that kind of nested loops with dependent variables, you immediately know that the complexity for each loop is linear.
For instance, in the following, f is called n*(n+1)*(n+2)/6 = O(n^3) times.
for (i = 1; i <= n; ++i) {
for (j = 1; j <= i; ++j) {
for (k = 1; k <= j; ++k) {
f();
}
}
}
First, simplify the code to show the main loops. So, we have a structure of:
for(int i = 0; i < n; i++) {
for(int k = 1; k <= n; k++) {
for(int j = 0; j < k; j++) {
}
}
}
The outer-loops run n * n times but there's not much you can do with this information because the complexity of the inner-loop changes based on which iteration of the outer-loop you're on, so it's not as simple as calculating the number of times the outer loops run and multiplying by some other value.
Instead, I would find it easier to start with the inner-loop, and then add the outer-loops from the inner-most to outer-most.
The complexity of the inner-most loop is k.
With the middle loop, it's the sum of k (the complexity above) where k = 1 to n. So 1 + 2 + ... + n = (n^2 + n) / 2.
With the outer loop, it's done n times so another multiplication by n. So n * (n^2 + n) / 2.
After simplifying, we get a total of O(n^3)
The time complexity for the above code is : n x n x n = n^3 + 1+ 1 = n^3 + 2 for the 3 loops plus the two constants. Since n^3 carries the heaviest growing rate the constant values can be ignored, so the Time complexity would be n^3.
Note: Take each loop as (n) and to obtained the total time, multiple the (n) values in each loop.
Hope this will help !

Complexity of algorithm

What is the complexity given for the following problem is O(n). Shouldn't it be
O(n^2)? That is because the outer loop is O(n) and inner is also O(n), therefore n*n = O(n^2)?
The answer sheet of this question states that the answer is O(n). How is that possible?
public static void q1d(int n) {
int count = 0;
for (int i = 0; i < n; i++) {
count++;
for (int j = 0; j < n; j++) {
count++;
}
}
}
The complexity for the following problem is O(n^2), how can you obtain that? Can someone please elaborate?
public static void q1E(int n) {
int count = 0;
for (int i = 0; i < n; i++) {
count++;
for (int j = 0; j < n/2; j++) {
count++;
}
}
}
Thanks
The first example is O(n^2), so it seems they've made a mistake. To calculate (informally) the second example, we can do n * (n/2) = (n^2)/2 = O(n^2). If this doesn't make sense, you need to go and brush up what the meaning of something being O(n^k) is.
The complexity of both code is O(n*n)
FIRST
The outer loop runs n times and the inner loop varies from 0 to n-1 times
so
total = 1 + 2 + 3 + 4 ... + n
which if you add the arithmetic progression is n * ( n + 1 ) / 2 is O(n*n)
SECOND
The outer loop runs n times and the inner loop varies from 0 to n-1/2 times
so
total = 1 + 1/2 + 3/2 + 4/2 ... + n/2
which if you add the arithmetic progression is n * ( n + 1 ) / 4 is also O(n*n)
First case is definitely O(n^2)
The second is O(n^2) as well because you omit constants when calculate big O
Your answer sheet is wrong, the first algorithm is clearly O(n^2).
Big-Oh notation is "worst case" so when calculating the Big-Oh value, we generally ignore multiplications / divisions by constants.
That being said, your second example is also O(n^2) in the worst case because, although the inner loop is "only" 1/2 n, the n is the clear bounding factor. In practice the second algorithm will be less than O(n^2) operations -- but Big-Oh is intended to be a "worst case" (ie. maximal bounding) measurement, so the exact number of operations is ignored in favor of focusing on how the algorithm behaves as n approaches infinity.
Both are O(n^2). Your answer is wrong. Or you may have written the question incorrectly.

Resources