Solving T(n) time complexity that contains "variables" - c++

So, I need to find the T(n) and then Big-O (tight upper bound) for the following piece of code:
int sum = 0;
for(int i = 1; i < n; i *= 2) {
for(int j = n; j > 0; j /= 2) {
for(int k = j; k < n; k += 2) {
sum += i + j * k;
}
}
}
Now from what I calculated for the loops, first loop runs log(n) times, second loop runs (log(n) * log(n)) times and the third loop is the one which is causing confusion, because I believe it runs for (n - j)/2 times. My question is can I assume it to be n/2 times, because I think it won't be a tight upper bound if I do that. Or is there a different approach that I am missing?

for(int i = 1; i < n; i *= 2) // (1)
for(int j = n; j > 0; j /= 2) // (2)
for(int k = j; k < n; k += 2) // (3)
For the first iteration of (3) (where k = j = n) no iteration will occur. After j is divided by 2 the third loop will run (n/2)/2 or n/4 times. After the third iteration of (2), (3) will run n/4/2 or n/8 times. We can sum the running time as follows:
n/4 + n/8 + n/16 + ... + n/2^k
This can also be written as:
n * (1/4 + 1/8 + 1/16 + ... + 1/2^k)
Which asymptotically is in O(n).

This is a very interesting question. Let give n a real number and see how it's going. Say, n=100. If we only look at the two inner loops
j k
100 None
50 50, 52, ..., 98
25 25, 27, ..., 99
12 12, 14, ..., 98
6 6, 8, ..., 98
3 3, 5, ..., 99
1 1, 3, ..., 99
As you can see, the complexity of the third loop is actually O(n). Especially when n is a very large number, it will be close to Θ(n)

Related

What is the big-O of this for loop...?

The first loop runs O(log n) time but the second loop's runtime depends on the counter of the first loop, If we examine it more it should run like (1+2+4+8+16....+N) I just couldn't find a reasonable answer to this series...
for (int i = 1; i < n; i = i * 2)
{
for (int j = 1; j < i; j++)
{
//const time
}
}
Just like you said. If N is power of two, then 1+2+4+8+16....+N is exactly 2*N-1 (sum of geometric series) . This is same as O(N) that can be simplified to N.
It is like :
1 + 2 + 4 + 8 + 16 + ....+ N
= 2 ^ [O(log(N) + 1] - 1
= O(N)

What is the Big-O Notation for this code?

I am having trouble deciding between N^2 and NlogN as the Big O? Whats throwing me off is the third nested for loop from k <=j. How do I reconcile this?
int Max_Subsequence_Sum( const int A[], const int N )
{
int This_Sum = 0, Max_Sum = 0;
for (int i=0; i<N; i++)
{
for (int j=i; j<N; j++)
{
This_Sum = 0;
for (int k=i; k<=j; k++)
{
This_Sum += A[k];
}
if (This_Sum > Max_Sum)
{
Max_Sum = This_Sum;
}
}
}
return Max_Sum;
}
This can be done with estimation or analysis. Looking at the inner most loop there are j-i operations inside the second loop. To get the total number of operations one would sum to get :
(1+N)(2 N + N^2) / 6
Making the algorithm O(N^3). To estimate one can see that there are three loops which at some point have O(N) calls thus it's O(N^3).
Let us analyze the most inner loop first:
for (int k=i; k <= j; k++) {
This_Sum += A[k];
}
Here the counter k iterates from i (inclusive) to j (inclusive), this thus means that the body of the for loop is performed j-i+1 times. If we assume that fetching the k-th number from an array is done in constant time, and the arithmetic operations (incrementing k, calculating the sum of This_Sum and A[k], and comparking k with j), then this thus runs in O(j-i).
The initialization of This_Sum and the if statement is not significant:
This_Sum = 0;
// ...
if (This_Sum > Max_Sum) {
Max_Sum = This_Sum;
}
indeed, if we can compare two numbers in constant time, and set one variable to the value hold by another value in constant time, then regardless whether the condition holds or not, the number of operations is fixed.
Now we can take a look at the loop in the middle, and abstract away the most inner loop:
for (int j=i; j < N; j++) {
// constant number of oprations
// j-i+1 operations
// constant number of operations
}
Here j ranges from i to N, so that means that the total number of operations is:
N
---
\
/ j - i + 1
---
j=i
This sum is equivalent to:
N
---
\
(N-j) * (1 - i) + / j
---
j=i
This is an arithmetic sum [wiki] and it is equivalent to:
(N - i + 1) × ((1 - i) + (i+N) / 2) = (N - i + 1) × ((N-i) / 2 + 1)
or when we expand this:
i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
So that means that we can now focus on the outer loop:
for (int i=0; i<N; i++) {
// i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
}
So now we can again calculate the number of operations with:
N
---
\
/ i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
---
i=0
We can use Faulhaber's formula [wiki] here to solve this sum, and obtain:
(N+1)×(N2+5×N+6)/6
or in expanded form:
N3/6 + N2 + 11×N/6 + 1
which is thus an O(n3) algorithm.

Finding the T(n) of An Algorithm

Okay so when my professor was going over it in class it seemed quite simple, but when I got to my homework I became confused. This is a homework example.
for (int i = 0; i < n; i++) // I know this runs at T(n)
for (int j = n - 1; j >= i; j--)
cout << i << " " << j << endl;
Here's an example I understand
for(int i=0; i<n-1; i++) {
for(int j=i+1; j<n; j++) {
1 Simple statement
}
For that example I just plugged in 0, 1, and 2. For 0, it ran for n-1, at 1 for n-2 and at 2 n-3. So I think that for the homework example if I plugged in 0 it would run for n+1 since j has to be greater than or equal to i which is 0. If it's not obvious, i'm pretty confused. If anyone could show me how to solve it, that'd make my day. Thanks guys.
Let's dig into the functon. Let's pick some numbers.
say, n = 5
So our code looks like this (magical pseudo-code uses INCLUSIVE loops, not that it's too important)
(1)for i = 0 to 4
(2)for j = 4 to i
(3)print i j
next
next
So this is a matter of preference, but usually loops are assumed to cost 1 simple statement per execution (comparison, and incrementation). So we'll assume that statements (1) and (2) have a cost of 2. Statement (3) has a cost of 1.
Now to determine T(n).
Our outer loop for i = 0 to 4 runs exactly n times.
Our inner loop for j = 4 to i . . . We'll dig in there for a minute.
For our example with n = 5 loop (2) will execute like so
j = 4; i = 0; j = 4; i = 1; j = 4; i = 2; j = 4; i = 3 j = 4; i = 4;
j = 3; i = 0; j = 3; i = 1; j = 3; i = 2; j = 3; i = 3;
j = 2; i = 0; j = 2; i = 1; j = 2; i = 2;
j = 1; i = 0; j = 1; i = 1;
j = 0; i = 0;
So it makes this kind of pyramid shape, where we do 1 less iteration each time. This particular example ran 5 + 4 + 3 + 2 + 1 = 15 times.
We can write this down as SUM(i; i = 0 to n).
Which we know from precalc: = (1/2)(n)(n+1).
And (3) will execute the exact same number of times as that inner loop since it's the only statement. So our total runtime is going to be. . .
COST(1) + COST(2) + COST(3)
(2)(n) + 2(1/2)(n)(n+1) + (1/2)(n)(n+1)
We can clean this up to be
(3/2)(n)(n+1) + 2n = T(n).
That said, this assumes that loops cost 2 and the statement costs 1. It's usually more meaningful to say loops cost 0 and statements cost 1. If that were the case, T(n) = (1/2)(n)(n+1).
And givent that T(n), we know T(n) is O(n^2).
Hope this helps!
It's not that hard.
3 examples for single loops:
for (int i = 0; i < n; i++)
for(int i = 0; i < n-1; i++)
for(int i = 2; i < n-1; i++)
The first loop executs it's content n times (i=0,1,2,3,...,n-1).
The same way, the second loop is just n-1 times.
The third would be n-3 because it starts not at 0, but 2
(and if n is less than 3, ie. n-3<0, it won't execute at all)
In a nested loop like
for(int i = 0; i < n-1; i++) {
for(int j = 0; j < n; j++) {
//something
}
}
For each pass of the outer loop, the whole inner loop is executed, ie. you can multiply both single loop counts to get how often "something" is executed in total. Here, it is (n-1) * n = n^2 - n.
If the inner loop depends on the value of the outer loop, it gets a bit more complicated:
for(int i = 0; i < n-1; i++) {
for(int j = i+1; j < n; j++) {
//something
}
}
The inner loop alone is n - (i+1) times, the outer one n-1 times (with i going from 0 to n-2).
While there are "proper" ways to calculate this, a bit logical thinking is often easier, as you did already:
i-value => inner-loop-time
0 => n-1
1 => n-2
...
n-2 => n - (n-2+1) = 1
So you´ll need the sum 1+2+3+...+(n-1).
For calculating sums from 1 to x, following formula helps:
sum[1...x] = x*(x+1)/2
So, the sum from 1 to n-1 is
sum[1...n-1] = (n-1)*(n-1+1)/2 = (n^2 - n)/2
and that´s the solution for the loops above (your second code).
About the first code:
Outer loop: n
Inner loop: From n-1 down to i included, or the other way from i up to <=n-1,
or from i up to <n, that´s n-i times
i >= innerloop
0 n
1 n-1
2 n-2
...
n-1 1
...and the sum from 1 to n is (n^2 + n)/2.
One easy way to investigate a problem is to model it and look at resulting data.
In your case, the question is: how many iterations does the inner loop depending on the the value of the outer loop variable?
let n = 10 in [0..n-1] |> List.map (fun x -> x,n-1-x);;
The 1 line above is the model showing what happens. If you now look at the resulting output, you will quickly notice something...
val it : (int * int) list =
[(0, 9); (1, 8); (2, 7); (3, 6); (4, 5); (5, 4); (6, 3); (7, 2); (8, 1);
(9, 0)]
What is it you notice? For a given N you run the outer loop N times - this is trivial. Now we need to sum up the second numbers and we have the solution:
sum(N-1..0) = sum(N-1..1) = N * (N-1) / 2.
So the total count of cout calls is N * (N-1) / 2.
Another easy way to achieve the same is to modify your function a bit:
int count(int n) {
int c = 0;
<outer for loop>
<inner for loop>
c++;
return c;
}

How many times increment will be executed?

I have the following code
int cnt = 0;
for (int i = 0; i < N; ++i)
{
for (int j = i + 1; j < N; ++j)
{
if(a[i] + a[j] == 0)
{ ++cnt;}
}
}
Where N is a number of elements in the array.
I started to learn algorithms and I trying to find how many times increment will be executed?
For i it will be N times.
For j it will be N-1 times when i = 0, N-2 when i = 1 etc.
So N-1 + N-2 + ... + 0 = ((0 + N-1)/2)*N = N*(N-1)/2
So how many times cnt++ will be executed?
To answer for this question we need to find how many times == will be executed? Of course it will be in range. From 0 to some value. And our final answer will be in the range from 0 + number of(++i) + number of(++j) to some value + number of(++i) + number of(++j).
Let's find this some value
It will be 1...N-1 when i=0, 2...N-2 when i=1 etc
so N-1 + N-2 + ... + 0 = N*(N-1)/2
So the answer will be from N*(N-1)/2 to N + N(N-1)/2 + N(N-1)/2, so from
N*(N-1)/2 to N^2
But R.Sedgwick said at the 33 slide that http://www.cs.princeton.edu/courses/archive/spring15/cos226/lectures/14AnalysisOfAlgorithms.pdf
the answer will be from N*(N+1)/2 to N^2
Why? Am I wrong? Where?
The inner loop (== test) is indeed executed N(N-1)/2 times.
For this reason, the increment (++cnt) is potentially executed between 0 and N(N-1)/2 times.
These two bounds can be reached: 0 when all a[k] > 0, and N(N-1)/2 when all a[k] == 0.
For the total count of increments, add N for the outer for loop and N(N-1)/2 for the inner for loop, and get between N(N+1)/2 and N² inclusive.

Compute the complexity of the following Algorithm? [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 8 years ago.
Compute the complexity of the following Algorithm?
I have the following code snippet:
i = 1;
while (i < n + 1) {
j = 1;
while (j < n + 1) {
j = j * 2;
}
i = i + 1;
}
plz explain it in detail
I want to know the the steps to solve the problem so I can solve such problems
Since j grows exponentially, the inner loop takes O(log(n)).
Since i grows linearly, the outer loop takes O(n).
Hence the overall complexity is O(n*log(n)).
i = 1;
while(i < n + 1){
j = 1;
While(j < n + 1){
j = j * 2:
}
i = i + 1;
}
outer loop takes O(n) since it increments by constant.
i = 1;
while(i < n + 1){
i = i + 1;
}
inner loop : j = 1, 2, 4, 8, 16, ...., 2^k
j = 2^k (k >= 0)
when will j stops ?
when j == n,
log(2^k) = log(n)
=> k * lg(2) = lg(n) ..... so k = lg(n).
While(j < n + 1){
j = j * 2;
}
so total O(n * lg(n))
You can simply understand outer-loop(with i) because it loops exactly n times. (1, 2, 3, ..., n). But inner-loop(j) is little difficult to understand.
Let's assume that n is 8. How much it loops? Starting with j = 1, it will be increased as exponentially : 1, 2, 4, 8. When j is over 8, loop will be terminated. It loops exactly 4 times. Then we can think general-form of this problem...
Think of that sequence 1, 2, 4, 8, .... If n is 2^k (k is non-negative integer), inner-loop will take k+1 times. (Because 2^(loop-1) = 2^k) Due to the assumption : n = 2^k, we can say that k = lg(n). So we can say inner-loop takes lg(n)+1 times.
When n is not exactly fit to 2^k, it takes one more time. ([lg(n)]+1) It's not a big deal with complexity though it has floor function. You can ingonre it this time.
So the total costs will be like this : n*(lg(n)+1). If you are familiar with Big-O notation, it can be expressed as : O(n lg n).
This one is similar to the following code :
for( int i = 1;i < n+1 ; i++){ // this loop runs n times
for(int j = 1 ; j<n+1 ; j=j*2){// this loop runs log_2(n)(log base 2 because it grows exponentially with 2)
//body
}
}
Hence in Big-Oh notation it is O(n)*O(logn) ; i.e, O(n*logn)
You can proceed like the following: