Understanding How Many Times Nested Loops Will Run - complexity-theory

I am trying to understand how many times the statement "x = x + 1" is executed in the code below, as a function of "n":
for (i=1; i<=n; i++)
for (j=1; j<=i; j++)
for (k=1; k<=j; k++)
x = x + 1 ;
If I am not wrong the first loop is executed n times, and the second one n(n+1)/2 times, but on the third loop I get lost. That is, I can count to see how many times it will be executed, but I can't seem to find the formula or explain it in mathematical terms.
Can you?
By the way this is not homework or anything. I just found on a book and thought it was an interesting concept to explore.

Consider the loop for (i=1; i <= n; i++). It's trivial to see that this loops n times. We can draw this as:
* * * * *
Now, when you have two nested loops like that, your inner loop will loop n(n+1)/2 times. Notice how this forms a triangle, and in fact, numbers of this form are known as triangular numbers.
* * * * *
* * * *
* * *
* *
*
So if we extend this by another dimension, it would form a tetrahedron. Since I can't do 3D here, imagine each of these layered on top of each other.
* * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * * *
* * *
*
These are known as the tetrahedral numbers, which are produced by this formula:
n(n+1)(n+2)
-----------
6
You should be able to confirm that this is indeed the case with a small test program.
If we notice that 6 = 3!, it's not too hard to see how this pattern generalizes to higher dimensions:
n(n+1)(n+2)...(n+r-1)
---------------------
r!
Here, r is the number of nested loops.

The 3rd inner loop is the same as the 2nd inner loop, but your n is a formula instead.
So, if your outer loop is n times...
and your 2nd loop is n(n+1)/2 times...
your 3rd loop is....
(n(n+1)/2)((n(n+1)/2)+1)/2
It's rather brute force and could definitely be simplified, but it's just algorithmic recursion.

The mathematical formula is here.
It is O(n^3) complexity.

This number is equal to the number of triples {a,b,c} where a<=b<=c<=n.
Therefore it can be expressed as a Combination with repetitions.. In this case the total number of combinations with repetitions is: n(n+1)(n+2)/6

1 + (1+2) + (1+ 2+ 3 ) +......+ (1+2+3+...n)

You know how many times the second loop is executed so can replace the first two loops by a single one right? like
for(ij = 1; ij < (n*(n+1))/2; ij++)
for (k = 1; k <= ij; k++)
x = x + 1;
Applying the same formula you used for the first one where 'n' is this time n(n+1)/2 you'll have ((n(n+1)/2)*(n(n+1)/2+1))/2 - times the x = x+1 is executed.

Related

How do I write the formula correctly in my comments?

I want to write this formula in comments:
And this is how I wrote the formula in comments:
// based on formula S = n/2 * (a + (a*n))
However if I'm comparing the comments with the formula then it's missing the Sn, a1 and the an part.
My question is: how do I write the formula correctly in my comments?
You should use a multi-line comment in your the code before the function or the code. for example:
/*
* Formula to calculate sum of n numbers
* S = n/2 * (a + l)
* where S is the sum of n elements
* n is the number of elements
* a is the first element in the series
* l is the nth element in the series
*/

Partition the array with minimal difference

Given an array A of N integers . I need to find X such that the difference between the following 2 values (A[1] * A[2] * ... * A[X]) and (A[X+1] * A[X+2] * ... * A[N]) is minimum possible i.e. I need to minimize | (A[1] * A[2] * ... * A[X]) - (A[X+1] * A[X+2] * ... * A[N]) | and if there are multiple such values of X, print the smallest one.
Constraints:-
1 <= N <= 10^5
1 <= A[i] <= 10^18.
I am not able to find the approach to solve this problem in efficient way.
What should be the best approach to solve this problem. Is there any special algorithm for multiplying large quantity of numbers.
The idea is to use a form of prefix and suffix products.
Let:
pre[i] = A[1] * A[2] * ... A[i] and
suf[i] = A[i] * A[i + 1] * ... A[N]
You can compute these arrays in O(n) time, as:
pre[i] = A[i] * pre[i - 1] with pre[1] = A[i] and
suf[i] = A[i] * suf[i + 1] with suf[N] = A[n]
Then, iterate from i = 1 to N and compute the maximum of:
abs(pre[i] - suf[i + 1])
Observe that pre[i] - suf[i + 1] is the same as:
(A[1] * A[2] * ... * A[i]) - (A[i + 1] * A[i + 2] ... * A[N])
which is exactly what you want to compute.
You can do it in O(n): first go - get the product of all elements of array (P) and the second go - assuming at start the left part is one and the second is P, on each step i multiply left on X[i] and divide right on X[i]. Continue the process until left is less than right.
Since you have large array of numbers, you need some big-number multiplication. So, maybe you better move to array of logarithms of A[i], LA[i] and move to new criteria.
Edit:
As mentioned by #CiaPan, the precision of standard 64-bit decimal is not enough for making log operation here (since values may be up to 10^18).
So to solve this problem you should first split values of the source array to pairs such that:
s[2*i] = a[i].toDouble / (10.0^9)
s[2*i+1] = a[i]/s[2*i]
Array s is twice longer than source array a, but its values do not exceed 10^9, so it is safe to apply log operation, then find desired sX for array s and divide it to 2 to get X for array a.
Extra-precision logarithm logic is not required.

For loop incremented by variable, time complexity

for (int i = 1; i < a; i++){
for(int j = 1; j < b; j = j + a){
Function() <-- O(1)
}
}
In this case, the outer loop will be executed 'a'times(O(a)), and
the inner loop will be executed 'b/a' times(O(b/a)).
Then the total time complexity will be O(a * b/a ) = O(b)?
I am not this interpretation is right or not..
Well O(a * b/a) = O(b) is obviously right because there is the identity right there: O(b*a/a) = O(b*1) = O(b).
However, it seems like the time complexity is O(a*b*1) (assuming looping causes no overheads in time). The computational effort increases linearly with each individual loop size. That is the reason for O(a*b).
I think it is a good question, my thought is
The original complexity should be O(a) * O(b/a)
But before you jump into conclusion, you have to judge the cases:
If b <= a, then O(b/a) = O(1), so O(a) * O(b/a) = O(a)
If b > a, then O(b/a) = O(b/a), so O(a) * O(b/a) = O(b)
So combined these cases, I would say it is O(max(a,b))
Armen is correct, the answer is O(ab). We can get the answer by these steps:
O((a-1)(b-1)(1))
=O(ab-a-b+1), which -a-b+1 can be ignored.
=O(ab)
O(b) is incorrect since you pass through the outer loop a times hence the answer must be at least O(a) (and, for all you know, b might be much smaller than a). The answer should depend on both a and b rather than b alone.
Counting carefully, you pass through the inner loop ceil((b-1)/a) times, hence the complexity is
O(a*ceil((b-1)/a))
But,
ceil((b-1)/a) <= (b-1)/a + 1
Thus
a*ceil((b-1)/a) <= a*((b-1)/a + 1) = b - 1 + a = a + b - 1
The 1 is asymptotically negligible, Hence the complexity is O(a+b).
Since O(a+b) = O(max(a,b)) this agrees with the answer of #shole.

Spoj - EverLast - Need Hint

I am trying to solve the SPOJ Problem EVERLAST, as given here,
The fate of the Pineapple
Currently what I am trying is:
1) After the first season the population = N * K
2) After the second season the population = N * K^2*(1-p)
since p is the probability that each pineapple is sterile and the initial N* K population dies out
3) After the third season the population = N * K^3 * (1-p)^2
a)The probability that pineapple population survives after second season = (1- p^(N * K)), since it dies out completely with a probability p^(N * K)
b)Probability that pineapple population survives after third season = 1 - p^ (N* K^2 *(1-p)), since it dies out completely with a probability p^(N * K^2 * (1-p))
and so on..
so the probability of population surviving forever will be
(1-p^(N * K)) * (1-p^(N * K^2 * (1-p))) * .......
But I am getting the wrong answer, I cant find the hints to this anywhere.
Where am I going wrong in my approach? any hints please?

Algorithm Big Omega

I am having trouble analyzing the following.
for b = 1 to n
for u = b to n
for i = b to u
Print
I am having trouble determining the worst-case runtime.
The first loop runs n times, the second loop runs (n(n+1))/2 times.
I then beleive that the third loop runs (n+1)/2 times.
However I have been told that it has a runtime of O(n^3).
Therefore it's best-case runtime can't be greater then the worst-case runtime!
I'm hoping for a push in the right direction if possible!
Thanks!
The third loop executes Print u-b+1 times {3} when it is activated.
When the second loop is activated, the third loop is activated for all u from b to n, i.e. executes Print 1+2+3+...n-b+1 times (substitute u=1, 2, 3...n in {3}). Using the formula for triangular numbers, this count equals (n-b+1)(n-b+2)/2 {2}.
When the first loop is activated, the second loop is activated for all b from 1 to n, i.e. executes Print n(n+1)/2 + (n-1)n/2 + (n-2)(n-1)/2 + ... 1 times (substitute b= 1, 2, 3... n in {2}; the counts are decreasing).
Using the formula for tetrahedral numbers, this equals n(n+1)(n+2)/6 {1}.
If you have trouble with this approach, you can simulate the Prints by hand instead.
For n=1
*
For n=2
*
* *
*
For n=3
*
* *
* * *
*
* *
*
For n=4
*
* *
* * *
* * * *
*
* *
* * *
*
* *
*
...
You clearly see the pattern of triangles of decreasing size. The area of the triangles grows as the square of the side. The total volume grows as the cube of the side.

Resources