Calculating the Time Complexity of nested loop with logarithmic increase - c++

I am learning at my own pace online. I was solving some examples but I can't wrap my mind around this one:
while(i<n)
{
for(int j=1; j<=i; j++)
sum = sum + 1;
i *=2;
}
I think the answer should be 2^n but my friend says nlog(n)
Can someone find the big-O for this loop and explain to me how to do so?

The outer loop will enter it's body log2(n) times, because i is increasing exponentially and thereby reaches the end n faster and faster. For example, if n were 1024, it would need only 10 iterations, with n=65536, it were 16 iterations. The accurate count is log2(n), but in terms of runtime complexity the logarithmic behaviour is enough. So here the complexity is O(log(n)).
The inner loop for(int j=1; j<=i; j++), each time when evaluated, will run to the corresponding i. It can be shown that the average run width is about n / log2(n), since i is 1, 2, 4, ... n with log2(n) steps. For example, if n is 31, i is 1, 2, 4, 8, 16, the sum is 31 with 5 steps. So it is permissible to take complexity O(n/log(n)) here.
The overal complexity is then O(log(n)*n/log(n)), which is O(n).

It's n.
if n=2^k then while complexity is k,
second loop : 2^1 + 2^2 + ... 2^k = 2^(k+1)-1 ~= 2^(k+1)
2^(k+1) = 2*n

We can assume without loss of generality that N is equal to 2^k + 1. We need to find the number of iterations of the inner loop. There will be k iterations of outer loop with 2^0, 2^1, ..., 2^k iterations of the inner loop. Let's sum up this values.

Related

Question regarding time complexity of nested for loops

Let n be a power of 2.
int sum = 0;
for (int i = 1; i < n; i *= 2)
for (int j = 0; j < n; j++)
sum += 1
Is the time complexity O(N) or O(nlogn). Thanks!
So first of all, it isn't necessary to know what kind of number is n is, since the asymptotic complexity is dependent of any arbitrary n(as long it is a positive integer).
We also know that the inner loop will do n iterations, hence we can denote the inner loop the time complexity of O(n).
About the outer loop. We know that at each iteration we double the values of i. Since i isn't zero at the initialization, it will for sure be increased by it doubling it. Since we are actually doubling i at each iteration we know that we reach n with exponentially increasingly larger iteration steps(for i=1, 2, 4, 8, 16, 32, 64, 128...). Hence the number of steps to reach n will become smaller while we get closer to it. Now knowing this we see that we are doing at most log(n) iterations to reach n.
Why? -> Well this might be mathematically informal, but I hope this is fine. In order to compute the number of iterations, one has to solve this equation: 2^x = n, where x is the number of iteration. We can see this basically by the explanation above. At each iteration step we double i until we reach n. The solution for x is than: x < log_2(n)
Hence the time complexity of the outer loop is O(log(n)).
Know this, one can simply multiply the complexities to O(log(n)n).

Can anyone suggest time complexity of the following code

According to me the time complexity should be O(nlogn) as the outer loop works until n/2^k =1 and inner loop works for n times. Can anyone tell if i'm correct or not.
while(n){
j=n;
while(j>1){
j-=1;
}
n/=2;
}
Inner cycle does n iterations, outer each iteration divides n by 2, so there are n + n/2 + n/4 + ... = 2n total iterations of the inner cycle and time complexity is O(n), not O(n log n).

Time complexity n^2

Is this O(N^2) or O(nlogn). Isnt it n^2 when there are nested loops?
int a[], N;
int f1(){ int i, j, sum=0;
for (i=1;; i=2*i)
{
If (i>=N) return sum;
for (j=1; j<2*i;j++) sum+=a[i];
}
This is O(N log N) as the outer loop is doubling the value of i in every iteration. So the complexity of outer loop is O(log N) instead of O(N).
If you had i++ or similar instead of i=2*i then the time complexity of two loops would have been O(n^2).
Edit: this is a simplified analysis. Please see the answer from R Sahu for more rigorous analysis.
Is this O(N^2) or O(nlogn).
It is neither.
Isnt it n^2 when there are nested loops?
That is true when you iterate over the items linearly. That is not true in your case.
In your case ...
The values of i are: 1 2 4 8 16 ... N
The inner loop is executed 2 + 4 + 8 + 16 + 32 ... N times.
That is a geometric series. The sum of a geometric series is a(1 - r^n)/(1 - r).
In your case, a is 2, r is 2, and n is log2(N) (log with base 2). Hence, the sum, after some simplification, is 2*2^(log2(N)), which is same as 2*N.
i.e your algorithmic complexity is O(N).
Thanks are due to #LedHead for correcting the error in the initial post.

Big O Notation for Algorithm

I'm busy doing an assignment and I'm struggling with a question. I know I'm not supposed to ask assignment questions outright so I understand if I don't get straight answers. But here goes anyway.
We must calculate the run time complexity of different algorithms, the one I'm stuck on is this.
for(int i = 1 ; i < n ; i++)
for(int j = 0 ; j < i ; j +=2)
sum++;
Now with my understanding, my first thought would be less than O(n2), because the nested loop isn't running the full n times, and still the j variable is incrementing by 2 each loop rather than iterating like a normal for loop. Although, when I did some code simulations with N=10, N=100, N=1000, etc. I got the following results when I outputted the sum variable.
N = 10 : 25,
N = 100 : 2500,
N = 1000 : 250000,
N = 10000 : 25000000
When I look at these results, the O Notations seems like it should be much larger than just O(n).
The 4 options we have been given in the assignment are : O(1), O(n2), O(n) and O(logn). As I said earlier, I cannot see how it can be as large as O(n2), but the results are pointing to that. So I just think I don't fully understand this, or I'm missing some link.
Any help would be appreciated!
Big O notation does not give you the number of operations. It just tells you how fast it will grow with growing input. And this is what you observe.
When you increased input c times, the total number of operations grows c^2.
If you calculated (nearly) exact number of operations precisely you would get (n^2)/4.
Of course you can calculate it with sums, but since I dunno how to use math on SO I will give an "empirical" explanation. Simple loop-within-a-loop with the same start and end conditions gives n^2. Such loop produces a matrix of all possible combinations for "i" and "j". So if start is 1 and end is N in both cases you get N*N combinations (or iterations effectively).
However, yours inner loop is for i < j. This basically makes a triangle out of this square, that is the 1st 0.5 factor, and then you skip every other element, this is another 0.5 factor; multiplied you get 1/4.
And O(0.25 * n^2) = O(n^2). Sometimes people like to leave the factor in there because it lets you compare two algorithms with the same complexity. But it does not change the ratio of growth in respect to n.
Bear in mind that big-O is asymptotic notation. Constants (additive or multiplicative) have zero impact on it.
So, the outer loop runs n times, and on the ith time, the inner loop runs i / 2 times. If it weren't for the / 2 part, it would be the sum of all numbers 1 .. n, which is the well known n * (n + 1) / 2. That expands to a * n^2 + b * n + c for a non-zero a, so it's O(n^2).
Instead of summing n numbers, we're summing n / 2 numbers. But that's still somewhere around (n/2) * ((n/2) + 1) / 2. Which still expands to d * n^2 + e * n + f for a non-zero d, so it's still O(n^2).
From your output it seems like:
sum ~= (n^2)/4.
This is obviously O(n^2) (actually you can replace the O with teta).
You should recall the definition for Big-O notation. See http://en.wikipedia.org/wiki/Big_O_notation.
The thing is that number of operations here is dependant on the square of n, even though the overall number is less than n². Nevertheless, the scaling is what matters for Big-O notation, thus it's O(n²)
With:
for (int i = 1 ; i < n ; i++)
for (int j = 0 ; j < i ; j +=2)
sum++;
We have:
0+2+4+6+...+2N == 2 * (0+1+2+3+...+N) == 2 * (N * (N+1) / 2) == N * (N+1)
so, with n == 2N, we have (n / 2) * (n / 2 + 1) ~= (n * n) / 4
so O(n²)
Your understanding regarding time complexity is not appropriate.Time Complexity is not only the matter of 'sum' variable.'sum' only calculates how many times the inner loop iterates,but you also have to consider total number of outer loop iterations.
now consider your program:
for(int i = 1 ; i < n ; i++)
for(int j = 0 ; j < i ; j +=2)
sum++;
Time complexity means running time of your program with respect to input values(here n).Here running time does not mean actual required time to execute your program in your computer .Actual required time varies from machine to machine.so to get a machine independent running time, Big O notation is very useful.Bog O actually comes from mathematics and it describes the running time in terms of mathematical functions.
The outer loop is executed total (n-1) times.for each of these (n-1) values (starting from i=1), the inner loop iterates i/2 times.so total number of inner loop iterations=1+1+2+2+3+3+...+(n/2)+(n/2)=2(1+2+3+...+n/2)=2*(n/2(n/2+1))/2=n^2/4+n/2.
similarly 'sum++' also executed total n^2/4+n/2 times.Now consider cost of line 1 of the program=c1,cost of line 2=c2 and cost of line 3=c3 .These casts can be different for different machine. so total time required for executing the program =c1*(n-1)+c2*(n^2/4+n/2)+c3*(n^2/4+n/2)=(c2+c3)n^2/4+(c2+c3)n/2+c1*n-c1.Thus the required time can be expressed in terms of mathematical function.In Big O notation you can say it is O((c2+c3)n^2/4+(c2+c3)n/2+c1*n-c1).In case of Big O notation, lower order terms and coefficient of highest order term can be ignored. because for large value of n ,n^2 is much greater than n. so you can say it is O((c1+c2)n^2/4).Also as for any value of n , n^2 is greater than (c1+c2)n^2/4 by a constant factor, so you can say it is O(n^2).

What is the algorithmic complexity of the code below

Is the Big-O for the following code O(n) or O(log n)?
for (int i = 1; i < n; i*=2)
sum++;
It looks like O(n) or am I missing this completely?
It is O(logn), since i is doubled each time. So at overall you need to iterate k times, until 2^k = n, and in this case it happens when k = logn (since 2^logn = n).
Simple example: Assume n = 100 - then:
iter1: i = 1
iter2: i = 2
iter3: i = 4
iter4: i = 8
iter5: i = 16
iter6: i = 32
iter7: i = 64
iter8: i = 128 > 100
It is easy to see that an iteration will be added when n is doubled, which is logarithmic behavior, while linear behavior is adding iterations for a constant increase of n.
P.S. (EDIT): mathematically speaking, the algorithm is indeed O(n) - since big-O notation gives asymptotic upper bound, and your algorithm runs asymptotically "faster" then O(n) - so it is indeed O(n) - but it is not a tight bound (It is not Theta(n)) and I doubt that is actually what you are looking for.
The complexity is O(logn) because the loops runs (log2n - 1) times.
O(log(n)), as you only loop ~log2(n) times
No the complexity is not linear. Try to play through a few scenarios: how many iterations does this cycle do for n = 2, n=4, n=16, n=1024? How about for n = 1024 * 1024? Maybe this will help you get the correct answer.
For loop check runs lg(n) +1 times. The inner loop runs lg(n) times. So, the complexity is is O(lg n), not O(log n).
If n==8, the following is how the code will run:
i=1
i=2
i=4
i=8 --Exit condition
It is O(log(n)).
Look at the code num++;
It loops O(log(n)) times.