Running time for following alorithm
int b = 0;
for (i = 0; i < n; i++)
for (j = 0; j < i * n; j++)
b = b + 5;
I know that the first loop is O(n) but that's about as far as I've gotten. I think that the second loop may be O(n^2) but the more I think about it the less sense it makes. Any guidance would be much appreciated.
We want to express the running time of this code as a function of n. Call this T(n).
We can say that T(n) = U(0,n) + U(1,n) + ... + U(n-1,n), where U(i,n) is the running time of the inner loop as a function of i and n.
The inner loop will run i * n times. So U(i,n) is just i * n.
So we get that T(n) = 0*n + 1*n + 2*n + ... + (n-1)*n = n * (1 + 2 + ... + (n-1)).
The closed form for (1 + 2 + ... + (n-1)) is just (n^2 - n)/2 http://www.wolframalpha.com/input/?i=1+%2B+2+%2B+...+%2B+(n-1) .
So we get that T(n) = n * (1 + 2 + ... + (n-1)) = n * ((n^2 - n)/2) = (n^3 - n^2) / 2,
which is O(n^3).
easiest way would be to use a example
assume n=10
1st for loop runs 10 times o(n)
2nd loop loop runs 0 if i=0
10 time for i=1
20 times for i=2
30 times for i=3
.... 100 times(for i=10) o(n^2)
hope it helps you
Outer loop runs for n iterations.
When n is 0, inner loop executes 0*n = 0 times
When n is 1, inner loop executes 1*n = n times
When n is 2, inner loop executes 2*n = 2n times
When n is 3, inner loop executes 3*n = 3n times
...
...
When n is n, inner loop executes n*n = n*n times
So it looks like inner loop executes a total of:
0 + n + 2n + 3n + ... + n*n
Multiply this with outer loop's n and you get approx. a O(n^3) complexity.
Statements Iterations
for (i = 0; i < n; i++) | n+1
for (j = 0; j < i * n; j++) | 0+n+2n+3n...n*n = n*n(n+1)/2
b = b + 5; | n*n(n+1)/2
So overall: O(n3)
Related
I'm stuck determining the big o notation for the below fragmented code, the given expression is part of I'm trying to figure out. I know given two plain, default for loops results in O(n^2) but the latter is entirely different. Here are the instructions.
The algorithm of
for (j = 0; j < n; j++)
{
for (k = j; k < n; k++)
{
}
}
will result in a number of iterations of given by the expression:
= n + (n-1) + (n-2) + (n-3) + ........ + (n - n)
Reduce the above series expression to an algebraic expression, without summation.
After determining the algebraic expression express the performance in Big O Notation.
You can use this method (supposedly applied by Gauss when he was a wee lad).
If you sum all the numbers twice, you have
1 + 2 + 3 + ... + n
+ n + (n-1) + (n-2) + ... + 1
—————————————————————————————————————--
(n+1) + (n+1) + (n+1) + ... + (n+1) = n(n+1)
Thus,
1 + 2 + 3 + ... + n = n(n+1)/2
and n(n+1)/2 is (n^2)/2 + n/2, so it is in O(n^2).
CODE:
void fun(int n){
if(n>2){
for(int i=0;i<n;i++){
j=0;
while(j<n){
cout<<j;
j++;
}
}
fun(n/2);
}
}
Here's what I think:
The recursive part is running log(n) times ?
and during each recursive call, the for loop will run n^2 times, with n changing to half in each recursive call.
So is it n^2 + (n^2)/4 + (n^2)/16 + ... + 1?
You are right, so the big(O) is n^2 since the sum of the series n^2 + (n^2)/4 + (n^2)/16 + ... + 1 never exceeds 2n^2
The number of writes to cout is given by the following recurrence:
T(N) = N² + T(N/2).
By educated guess, T(N) can be a quadratic polynomial. Hence
T(N) = aN²+bN+c = N² + T(N/2) = N² + aN²/4+bN/2+c.
By identification, we have
3a/4 = 1
b/2 = 0
c = c.
and
T(N) = 4N²/3 + c.
With T(2)= 0,
T(N) = 4(N²-4)/3
which is obviously O(N²).
This is simple mathematics. The complexity is n^2 + (n^2)/4 + (n^2)/16 + ... + 1. It is (n² * (1 + 1/4+ ...)) . And the maths says that the infinite serie converges to 4/3 (the formula is: 1 / (1 - 1/4)).
It gives actually O(n2).
I have a c[N][M] matrix where I apply a max-sum operation over a (K+1)² window. I am trying to reduce the complexity of the naive algorithm.
In particular, here's my code snippet in C++:
<!-- language: cpp -->
int N,M,K;
std::cin >> N >> M >> K;
std::pair< unsigned , unsigned > opt[N][M];
unsigned c[N][M];
// Read values for c[i][j]
// Initialize all opt[i][j] at (0,0).
for ( int i = 0; i < N; i ++ ) {
for ( int j = 0; j < M ; j ++ ) {
unsigned max = 0;
int posX = i, posY = j;
for ( int ii = i; (ii >= i - K) && (ii >= 0); ii -- ) {
for ( int jj = j; (jj >= j - K) && (jj >= 0); jj -- ) {
// Ignore the (i,j) position
if (( ii == i ) && ( jj == j )) {
continue;
}
if ( opt[ii][jj].second > max ) {
max = opt[ii][jj].second;
posX = ii;
posY = jj;
}
}
}
opt[i][j].first = opt[posX][posY].second;
opt[i][j].second = c[i][j] + opt[posX][posY].first;
}
}
The goal of the algorithm is to compute opt[N-1][M-1].
Example: for N = 4, M = 4, K = 2 and:
c[N][M] = 4 1 1 2
6 1 1 1
1 2 5 8
1 1 8 0
... the result should be opt[N-1][M-1] = {14, 11}.
The running complexity of this snippet is however O(N M K²). My goal is to reduce the running time complexity. I have already seen posts like this, but it appears that my "filter" is not separable, probably because of the sum operation.
More information (optional): this is essentially an algorithm which develops the optimal strategy in a "game" where:
Two players lead a single team in a N × M dungeon.
Each position of the dungeon has c[i][j] gold coins.
Starting position: (N-1,M-1) where c[N-1][M-1] = 0.
The active player chooses the next position to move the team to, from position (x,y).
The next position can be any of (x-i, y-j), i <= K, j <= K, i+j > 0. In other words, they can move only left and/or up, up to a step K per direction.
The player who just moved the team gets the coins in the new position.
The active player alternates each turn.
The game ends when the team reaches (0,0).
Optimal strategy for both players: maximize their own sum of gold coins, if they know that the opponent is following the same strategy.
Thus, opt[i][j].first represents the coins of the player who will now move from (i,j) to another position. opt[i][j].second represents the coins of the opponent.
Here is a O(N * M) solution.
Let's fix the lower row(r). If the maximum for all rows between r - K and r is known for every column, this problem can be reduced to a well-known sliding window maximum problem. So it is possible to compute the answer for a fixed row in O(M) time.
Let's iterate over all rows in increasing order. For each column the maximum for all rows between r - K and r is the sliding window maximum problem, too. Processing each column takes O(N) time for all rows.
The total time complexity is O(N * M).
However, there is one issue with this solution: it does not exclude the (i, j) element. It is possible to fix it by running the algorithm described above twice(with K * (K + 1) and (K + 1) * K windows) and then merging the results(a (K + 1) * (K + 1) square without a corner is a union of two rectangles with K * (K + 1) and (K + 1) * K size).
I have this c++ like pseudo code here:
for ( i = 1; i ≤ (n – 2); i++)
for (j = i + 1; j ≤ (n – 1); j ++)
for (k = j + 1; k ≤ n; k++)
Print “Hello World”;
I am fairly certain the time complexity of this particular block of code is O(n^3) because it is triple nested for loop and they are all going to at minimum n - 2 so I generalized (n-2) * (n-1) * n
But I have been trying to solve the actual time complexity function. This is how far I got and could not proceed any further:
summation from i = 1 to n-2, summation from j = (i+1) to n-1, summation from k = (j+1) to n.
I understand that the inner most loop performs n - (j+1) steps, the middle loop performs (n-1)-(i+1) steps, and the outer loop performs (n-2)-i steps. I just need some pointers on how to simplify the summations to come to a time complexity function.
Thank you!
If interested, the loops iterate through every combination of n things taken 3 at a time, starting with (1,2,3), (1,2,4), ... , and ending with (n-2,n-1,n), which is n! / (( 3! )( (n-3)!) ) = (n)(n-1)(n-2)/6 = (n^3 - 3n^2 + 2n) / 6 , which leads to O(n^3).
Don't run the loop from 1 to less or equal a value. Your code is equal to:
for ( i = 0; i < (n – 2); i++)
for (j = i; j < (n – 1); j ++)
for (k = j; k < n; k++)
Print “Hello World”;
So your inner loop runs n-j, the middle one multiplies it with n-1-i and the outer one multiplies it with n-2. So you get (n-j)*(n-1-i)*(n-2). n has O(n) complexity. Because of i runs from 0 to (n-1), you could replace it with O(n) (because sum(0, n) = 0 + 1 + .. + N = 0.5 * n^2 = O(n^2)). It is the same with j. So you get (O(n)-O(n))*(O(n)-1-O(n))*(O(n)-2) = O(n)*(n)*O(n) = O(n^3).
For details why you could replace i with O(n) see "Nested loops" at this.
Say we have 3 numbers N, x and y which are always >=1.
N will be greater than x and y and x will be greater than y.
Now we need to find the sum of all number between 1 and N that are divisible by either x or y.
I came up with this:
sum = 0;
for(i=1;i<=N;i++)
{
if(i%x || i%y)
sum += i;
}
Is there a way better way of finding the sum avoiding the for loop?
I've been pounding my head for many days now but have not got anything better.
If the value of N has a upper limit we can use a lookup method to speedup the process.
Thanks everyone.
I wanted a C/C++ based solution. Is there a built-in function to do this? Or do I have to code the algorithm?
Yes. You can void the for loop altogether and find the sum in constant time.
According to the Inclusion–exclusion principle summing up the multiples of x and multiples of y and subtracting the common multiple(s) that got added twice should give us the required sum.
Required Sum = sum of ( multiples of x that are <= N ) +
sum of ( multiples of y that are <= N ) -
sum of ( multiples of (x*y) that are <= N )
Example:
N = 15
x = 3
y = 4
Required sum = ( 3 + 6 + 9 + 12 + 15) + // multiples of 3
( 4 + 8 + 12 ) - // multiples of 4
( 12 ) // multiples of 12
As seen above we had to subtract 12 as it got added twice because it is a common multiple.
How is the entire algorithm O(1)?
Let sum(x, N) be sum of multiples of x which are less than or equal to N.
sum(x,N) = x + 2x + ... + floor(N/x) * x
= x * ( 1 + 2 + ... + floor(N/x) )
= x * ( 1 + 2 + ... + k) // Where k = floor(N/x)
= x * k * (k+1) / 2 // Sum of first k natural num = k*(k+1)/2
Now k = floor(N/x) can be computed in constant time.
Once k is known sum(x,N) can be computed in constant time.
So the required sum can also be computed in constant time.
EDIT:
The above discussion holds true only when x and y are co-primes. If not we need to use LCM(x,y) in place of x*y. There are many ways to find LCM one of which is to divide product by GCD. Now GCD cannot be computed in constant time but its time complexity can be made significantly lesser than linear time.
If a number is divisible by X, it has to be a multiple of x.
If a number is divisible by Y, it has to be a multiple of y.
I believe, if you do a for loop for all multiples of x and y, and avoid any duplicates, you should get the same answer.
Out of my head, something of the type:
sum = 0
for( i=x; i<=n; i+=x)
sum += i;
for( i=y; i<=n; i+=y)
if( y % x != 0 )
sum += i;