Figuring out Big(o) - time

for (int i = 0; i < n; i++)
{
for (int j = 0; j < i*i; j++)
{
cout << j << endl;
result++;
}
}
Running this code say for 5 it runs a total of 30 times. I know the outer loop runs N. the inner loop though is giving me some trouble since it's not n*n but i*i and I haven't seen one like this before trying to figure out T(n), and Big(O).

This algorithm is O(n^3): To realise this we have to figure out how often the inner code
cout << j << endl;
result++;
is executed. For this we need to sum up 1*1+2*2+...+n*n = n^3/3+n^2/2+n/6 which is a well known result (see e.g. Sum of the Squares of the First n Natural Numbers). Thus O(T(n)) = O(1*1+2*2+...+n*n) = O(n^3) and the (time) complexity of the algorithm is therefore O(n^3).
Edit: If you're wondering why this is sufficient (see also Example 4 in Time complexity with examples) it is helpful to rewrite your code as a single loop so we can see that the loops add a constant amount of instructions (for each run of the inner code):
int i = 0;
int j = 0;
while(i < n) {
cout << j << endl;
result++;
if(j < i * i) j++; //were still in the inner loop
else {//start the next iteration of the outer loop
j = 0;
i++;
}
}
Thus the two loops 'add' the two comparisons plus the if-statement which simply makes the conditional jumps and their effects more explicit.

Related

Time Complexity for for loop with if-else block

I want to find the time complexity for this below code. Here's my understanding-
The outer for loop will loop 2n times and in the worst case when i==n, we will enter the if block where the nested for loops have complexity of O(n^2), counting the outer for loop, the time complexity for the code block will be O(n^3).
In best case when i!=n, else has complexity of O(n) and the outer for loop is O(n) which makes the complexity, in best case as O(n^2).
Am I correct or am I missing something here?
for (int i = 0; i < 2*n; i++)
{
if (i == n)
{
for (int j = 0; j < i; j++)
for (int k = 0; k < i; k++)
O(1)
}
else
{
for (int j = 0; j < i; j++)
O(1)
}
}
No.
The question "what is T(n)?".
What you are saying is "if i=n, then O(n^3), else O(n^2)".
But there is no i in the question, only n.
Think of a similar question:
"During a week, Pete works 10 hours on Wednesday, and 1 hour on every other day, what is the total time Pete works in a week?".
You don't really answer "if the week is Wednesday, then X, otherwise Y".
Your answer has to include the work time on Wednesday and on every other day as well.
Back in your original question, Wednesday is the case when i=n, and all other days are the case when i!=n.
We have to sum them all up to find the answer.
This is a question of how many times O(1) is executed per loop. The time complexity is a function of n, not i. That is, "How many times is O(1) executed at n?"
There is one run of a O(n^2) loop when i == n.
There are (2n - 2) instances of the O(n) loop in all other cases.
Therefore, the time complexity is O((2n - 2) * n + 1 * n^2) = O(3n^2 - 2*n) = O(n^2).
I've written a C program to spit out the first few values of n^2, the actual value, and n^3 to illustrate the difference:
#include <stdio.h>
int count(int n){
int ctr = 0;
for (int i = 0; i < 2*n; i++){
if (i == n)
for (int j = 0; j < i; j++)
for (int k = 0; k < i; k++)
ctr++;
else
for (int j = 0; j < i; j++)
ctr++;
}
return ctr;
}
int main(){
for (int i = 1; i <= 20; i++){
printf(
"%d\t%d\t%d\t%d\n",
i*i, count(i), 3*i*i - 2*i, i*i*i
);
}
}
Try it online!
(You can paste it into Excel to plot the values.)
The First loop is repeated 2*n times:
for (int i = 0; i < 2*n; i++)
{
// some code
}
This part Just occur once, when i == n and time complexity is : O(n^2):
if (i == n)
{
for (int j = 0; j < i; j++)
for (int k = 0; k < i; k++)
O(1)
}
And this part is depends on i.
else
{
for (int j = 0; j < i; j++)
O(1)
}
Consider i when:
i = 0 the loop is repeated 0 times
i = 1 the loop is repeated 1 times
i = 2 the loop is repeated 2 times
.
.
i = n the loop is repeated n times. (n here is 2*n)
So the loop repeated (n*(n+1)) / 2 times But when i == n else part is not working so (n*(n+1)) / 2 - n and time complexity is O(n^2).
Now we sum all of these parts: O(n^2) (first part) + O(n^2) (second part) because the first part occurs once so it's not O(n^3). Time complaxity is: O(n^2).
Based on #Gassa answer lets sum up all:
O(n^3) + O((2n)^2) = O(n^3) + O(4n^2) = O(n^3) + 4*O(n^2) = O(n^3)
Big O notation allows us throw out 4*O(n^2) because O(n^3) "eats" it

Big O Time Complexity for nested loops

What is the time complexity for the below code?
int i = 0;
while(i*i <=N) {
for(int j = 0; j <=N; j++) {
for(int k = 0; k <=N; k++, i++) {
//O(1) operation
}
}
i++;
}
In nested loops if the outer loop 1 takes O(1) time and inner loop 2 takes O(logn) time and inner loop 3 takes O(n).
Then the total T.C. is O(1)O(logn)O(n) = O(nlogn). Is it true?
Please explain.
tl;dr: This code runs in O(n^2).
Detailed answer:
The outer "loop": while (i*i <= M) is a distraction.
Because i increases itself for each iteration of the most inner loop - it means by the time you re-evaluate the condition in it, the value of i is going to be N*N. This means, the outer loop is always repeating itself only once.
Now, once you ignore it, it is easy to see that the time complexity of the remaining code is O(N^2), since it's basically can be rewritten as:
int i = 0;
if (i * i <= N) { // Since the while loop does not repeat more than once
for(int j = 0; j <=N; j++) {
for(int k = 0; k <=N; k++, i++) {
//O(1) operation
}
}
i++;
}
Note: This answer assume no overflows of the variables, and specifically i does not overflow
Big O Time Complexity for nested loops
The operation "//O(1) operation" is executed (N+1)^2 times. And the number of times the calculations done by the loops themselves (e.g. performing the test j<=N) is also square (N^2+a*N+b).
So the time complexity is O(N^2).
You can test that by extending your program the following way:
int i=0;
int count=0;
while(i*i <= N)
{
for(int j=0; j<=N; j++)
{
for(int k=0; k<=N; k++, i++)
{
count++;
}
}
i++;
printf("i after the while() loop: %d\n",i);
}
printf("Number of steps: %d\n",count);
You test your program with different values of N and you can see that:
i is (N+1)^2+1 after the first pass of the while() loop. This means that the condition i*i<=N is equal to (N+1)^4 + 2*N^2 + 3*N <= (-2). And this is always false for N>=0.
The operation count++ (representing ourt O(1) operation) is done (N+1)1^2 times.
Time Complexity
Such kind of questions are typically asked on the CS Stack Exchange web site, not on StackOverflow.
StackOverflow is intended for questions about writing computer programs only.
(Note that StackOverflow is part of the StackExchange network and you can use all StackExchange web sites with your user account.)

Confusion about complexity of two dependent loops?

for(i=1; i < n; i++){
for(j=1; j <= i; j++){
statement1;
}
}
outer loop = O(N)
Inner loop = N(N-1)/2
Total = N*N(N-1)/2 = N^3
it seems n^3 is complexity of these nested loops. but accordings to books, its complexity is n^2 from N(N-1)/2 .
The only interesting thing to count is how often statement1 will be executed.
Therefore, note that something like
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
statement1;
triggers 2 * 3 = 6 executions. So you count how often the inner loop gets executed per outer loop iteration.
However, in your example you did a mistake and multiplied the iterations of the outer loop with the total iterations of the inner loop, not the number of iterations per outer loop iteration.
In the example above that would be like 2 * 6 = 12 instead of only 2 * 3 = 6.
Let's take a closer look at what happens in your specific example. The outer loop triggers n iterations of the inner loop. The inner loop first yields 1 iteration. In the next iteration of the outer loop it will yield 2 iterations, then 3 and so on.
In total you will thus receive 1 + 2 + ... + n = (n^2 - n)/2 iterations of the inner loop. Again, note the 'in total'. So statement1 will in total be executed (n^2 - n)/2 times. The outer loops iterations are already taken into account for the computation of the inner loops total runs, no additional multiplication.
(n^2 - n)/2 is obviously in O(n^2) due to its asymptotic complexity. Intuitively only the biggest factor plays a role, we can drop other stuff by estimating with <=.
(n^2 - n)/2
<= n^2 - n
<= n^2 in O(n^2)
for(i=1; i < n; i++){
for(j=1; j <= i; j++){
statement1;
}
}
In order to simplify the problem, let's assume that n is 5 here.
So line 1 will execute 5 times since it will check and increment i value 5 times.
line 2 will execute (5-1)=4 times because for i=5, it will not execute but line 1 will execute for i=5.
line 3 will execute for 1 time, 2 times 3 times and so on, each time i is incremented.
Take complexity of 3rd line into context and you'll find that it is executing 1+2+3+4=10 times. It's simply the sum of numbers from 1 to 4 or you can say, n(n+1)/2 where n=4.
We can ignore the complexity of line 1 and line 2 since they are constant and in asymptotic notation , the complexity will be O(n^2).
You can think about the 2 nested loops as checking all the cells on the diagonal and below the diagonal on a N x N matrix.
So you'll always do a number of operations close to 1/2 of N^2. So the total number of operations of your code will be N^2 * constant. By the definition of Big-O notation, that means that your code runtime complexity is O(n^2).
Here is a simple code to help you understand my explanation.
#include <vector>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;
// These function count the number of times that your code will execute statement1
int count(int N){
int total = 0;
for(int l = 0; l < N; ++l){
for(int r = 0; r <= l; ++r){
total++;
}
}
return total;
}
// this code will show the cells of the matrix that you are "executing"
int showMatrix(int N){
vector<vector<bool> > mat(N, vector<bool>(N, false) );
for(int l = 0; l < N; ++l){
for(int r = 0; r <= l; ++r){
mat[l][r] = true;
}
}
for(int line = 0; line < N; ++line){
for(int column = 0; column < N; ++column){
cout << (mat[line][column] == true ? "1 " : "0 ");
}
cout << endl;
}
}
int main(){
showMatrix(10);
cout << count(10) << endl;
return 0;
}

Questions on analyzing time complexity

Hi I have some doubts about my analysis on the following two code fragment:
1)
for (i = 1; i <= 1.5n; i++)
for (j = n; j >= 2; j--)
cout << i, j;
The outer loop will be executed 1.5n times, and the inner loop will be executed n-2 times. Therefore, the complexity is O(1.5n*(n-2) = O(n^2)?
2)
j = 1;
while (j < n/2) {
i = 1;
while (i < j) {
cout << j << i;
i++;
}
j++;
}
The outer while loop will be executed n/2 times, and the inner while loop will be executed 1+2+...+n/2 times. Therefore, the complexity is also O(n^2)?
I was not so sure about my analysis on second problem.
Thank you so much for the help!
You're right. The right solution is to count.
Note that:
j = 0;
while (j < n/2) {
j++;
}
has a O(n)complexity, whereas:
j = 1;
while (j < n) {
j *= 2;
}
has a O(log n) complexity.

Identify and state the running time using Big-O

For each of the following algorithms, identify and state the running time using Big-O.
//i for (int i = 0; Math.sqrt(i) < n; i++)
cout << i << endl;
//ii for (int i = 0; i < n; i++){
cout << i << endl;
int k = n;
while (k > 0)
{
k /= 2;
cout << k << endl;
} // while
}
//iii
int k = 1;
for (int i = 0; i < n; i++)
k = k * 2;
for (int j = 0; j < k; j++)
cout << j << endl;
I've calculate the loop times for the first question using n=1 and n=2. The loop in i will run n^2-1 times. Please help and guide me to identify the Big-O notation.
(i) for (int i = 0; Math.sqrt(i) < n; i++)
cout << i << endl;
The loop will run until squareRoot(i) < N , or until i < N^2. Thus the running time will be O(N^2), ie. quadratic.
(ii) for (int i = 0; i < n; i++){
cout << i << endl;
int k = n;
while (k > 0)
{
k /= 2;
cout << k << endl;
} // while
}
The outer loop will run for N iterations. The inner loop will run for logN iterations(because the inner loop will run for k=N, N/2, N/(2^2), N/(2^3), ...logN times). Thus the running time will be O(N logN), ie. linearithmic.
(iii)
int k = 1;
for (int i = 0; i < n; i++)
k = k * 2;
for (int j = 0; j < k; j++)
cout << j << endl;
The value of k after the execution of the first loop will be 2^n as k is multiplied by 2 n times. The second loop runs k times. Thus it will run for 2^n iterations. Running time is O(2^N), ie. exponential.
For the first question, you will have to loop until Math.sqrt(i) >= n, that means that you will stop when i >= n*n, thus the first program runs in O(n^2).
For the second question, the outer loop will execute n times, and the inner loop keeps repeatedly halving k (which is initially equal to n). So the inner loop executes log n times, thus the total time complexity is O(n log n).
For the third question, the first loop executes n times, and on each iteration you double the value of k which is initially 1. After the loop terminates, you will have k = 2^n, and the second loop executes k times, so the total complexity will be O(2^n)
Couple hints may allow you to solve most of running time complexity problems in CS tests/homeworks.
If something decrease by a factor of 2 on each iteration, that's a log(N). In your second case the inner loop index is halved each time.
Geometric series,
a r^0 + a r^1 + a r^2 ... = a (r^n - 1) / (r - 1).
Write out third problem:
2 + 4 + 8 + 16 ... = 2^1 + 2^2 + 2^3 + 2^4 + ...
and use the closed form formula.
Generally it helps to look for log2 and to write few terms to see if there is a repeatable pattern.
Other common questions require you to know factorials and its approximation (Sterling's approximation)
Using Sigma Notation, you can formally obtain the following results:
(i)
(ii)
(iii)

Resources