how many times will this loop execute - java

I was just wondering how many times a nested loop like this would run
int sum = 0;
for(int i = 0; i < total; i++) {
for(int j = i + 1; j < total; j++) {
for(int k = j; k < total; k++) {
sum++;
}
}
}
System.out.println(sum);
I can easily see the output of sum, but I would like to be able to mathematically calculate the total of sum with any number for total.

TL;DR
The loop will be executed for ((total ^ 3) - total) / 6 times and hence that will be the value of sum at the end of the loop.
int sum = 0;
for(int i = 0; i < total; i++) {
for(int j = i + 1; j < total; j++) {
for(int k = j; k < total; k++) {
sum++;
}
}
}
It is easy to see that the outer loop runs for a total times. The second loop is the trickier one
Let's try to work this out
i = 0, j runs from 1..total - 1
i = 1, j runs from 2..total - 1
i = 2, j runs from 3..total - 1
...
i = total - 2, j runs from total - 1 ..total - 1 (will only run once)
i = total - 1, inner loop does not execute as the loop termination condition is true.
The third loop is dependent on the second inner loop - k runs from j..total - 1
Let us take total as 6
j runs from 1..5 -> k runs for 5 times (j = 1) + 4 times(j = 2) + 3 times(j = 3)+ 2 times(j = 4) + 1 time(j = 4)
(Showing a minified version for others)
2..5 -> 4+3+2+1
3..5 3+2+1
4..5 2+1
5..5 1
Which is
1 + 2 + 3 + 4 + 5+
1 + 2 + 3 + 4 +
1 + 2 + 3 +
1 + 2 +
1
Generally,
1 + 2 + 3 + .. n +
1 + 2 + 3 +..n - 1+
1 + 2 + 3 +..n - 2+
1 + 2 + 3 +
1 + 2 +
1
This boils down to the sum
n * (n - 1)) / 2
For all values of n ranging from 1 to total
This can be verified with the below
int res = 0;
for (int i = 1; i <= total; i++) {
res += (i * (i - 1))/2;
}
res will be equal to your sum.
Mathematically, the above is
((total ^ 3) - total) / 6
Derivation:
References:
Sums of the First n Natural Numbers
Sum of the Squares of the First n Natural Numbers

The first iteration of the middle loop adds
total-1 + total-2 + ... + 1
to the sum.
The second iteration of the middle loop adds
total-2 + total - 3 + ... + 1
to the sum
The last iteration of the middle loop adds
1
to the sum.
If you sum all of these terms, you get
(total - 1) * 1 + (total - 2) * 2 + (total - 3) * 3 + ... + 2 * (total - 2) + 1 * (total - 1)
It's been a while since I studied math, so I don't remember if there's a simpler formula for this expression.
For example, if total is 10, you get:
9 * 1 + 8 * 2 + 7 * 3 + 6 * 4 + 5 * 5 + 4 * 6 + 3 * 7 + 2 * 8 + 1 * 9 =
9 + 16 + 21 + 24 + 25 + 24 + 21 + 16 + 9 =
165

It needs only a little bit knowledge of programming.Actually logic that is running behind is only computational kind of thing.
let's say:
total=10,sum=0
- when i is 0:
That time j is initialised with 1(i+1) and k as well. So k will lead us to execute the loop 9 times and and as j is incremented ,it will lead us to execute sum statement 8 times and 7 times and further 6 times till 1 time. (9+8+7+6+5+4+3+2+1=45 times.)
- when i is 1:
That time j is initialised with 2 and k as well.So sum statement is going to execute 8 times and then 7 times and then 6 times till 1.
(8+7+6+5+4+3+2+1=36 times).
- when i is 2:
Same thing happens repeatedly but starting with difference number ,so this time (7+6+5+4+3+2+1=28)
So this sequence continues until there is significance of occuring the condition with trueness.
This happens till i is 9.
So the final answer is 1+3+6+10+15+21+28+36+45=165.

The equation is like below
and the k is equal to total :

outermost loop runs 'total' number of times.
for each outer loop , middle loop runs 'total-i' times.
i.e total * total+total * (total-1)+total * (total-2)....total * 1
= total*(total+total-1+total-2...1)
= total*(1+2+3....total)
= total*(sum of first 'total' natural numbers)
= total*(total*(total+1)/2)
now the innermost loop also runs 'total-j' times for each middle loop
i.e
total*(total*(total+1)/2)*(total+(total-1)+(total-2)....+1)
= total*(total*(total+1)/2)*(1+2+3....+total)
= total*(total*(total+1)/2)* (sum of first 'total' natural numbers)
= total*(total*(total+1)/2) * (total*(total+1)/2)..
So finally you will get something close to
total * (total*(total+1)/2) * (total*(total+1)/2).
Sorry there's a correction as #andreas mentioned innermost and middle loops run only till total-i-1 times
in which case it will be the sum of first (total-1) no.s which should be (total-1)*total/2 so the final output should be
total * (total*(total-1)/2) * (total*(total-1)/2) .

As we know, the sum of an arithmetic progression is:
The inner-most loop will loop for
times, which is a function to j.
You sum it up and get a function to i, aka:
You sum it up again and get a function to total, aka:
For Mathematica users, the result is:
f[x_]:=Sum[Sum[x-j,{j,i+1,x-1}],{i,0,x-1}]
From here, we can see it more clearly, and the FINAL result is:
where x is total.

That function will loop (total/6)*(total*total - 1) times
The snippet bellow just verifies that
var total = 100
var sum = 0;
for(var i = 0; i < total; i++) {
for(var j = i + 1; j < total; j++) {
for(var k = j; k < total; k++) {
sum++;
}
}
}
function calc(n) {
return n*(n-1)*(n+1)/6
}
console.log("sum: "+sum)
console.log("calc: "+calc(total))

If we run this loop 100 times and generate a data set, then graph it, we get this:
Now, this graph is clearly a cubic. So we can do a solve using the cubic equation of ax^3+bx^2+cx+d.
Using 4 points, the values of them all are:
So the full equation is
y=x^3/6-x/6
y=x(x^2/6-1/6)
y=(x/6)(x^2-1)
Interactive Graph:
<iframe src="https://www.desmos.com/calculator/61whd83djd?embed" width="500px" height="500px" style="border: 1px solid #ccc" frameborder=0></iframe>

A simple loop like this:
for (i = a; i < b; i ++) {
....
}
runs b-a iterations (i takes the values: a, a+1, a+2... b-2, b-1) if a < b and 0 iterations otherwise. We will assume below that a < b always.
Its number of iterations can be compute using the simple maths formula:
Applying the formula to your code
We start with the innermost loop:
for(int k = j; k < t; k++) {
sum++;
}
Its number of iterations is:
Using the formula above, the value of U is (t-1)-j+1 which means:
U = t - j
Adding the middle loop
Adding the middle loop, the number of iterations becomes:
The terms of the second sum are t-(i+1), t-(i+2), ... t-(t-2), t-(t-1).
By solving the parentheses and putting them in the reverse order they can be written as:
1, 2, ... t-i-2, t-i-1.
Let p = t - j. The second sum now becomes:
It is the sum of the first t-i-1 natural numbers and its value is:
Adding the outer loop
Adding the outer loop the sum becomes:
On the last sum, the expression (t - i) starts with t (when i = 0), continues with t-1 (when i = 1) and it keeps decreasing until it reaches 1 (when i = t - 1). By replacing q = t - i, the last sum becomes:
The last expression subtracts the sum of the first n natural numbers from the sum of the first n square numbers. Its value is:
Now it's easy to simplify the expression:
The final answer
The number of iterations of the posted code is:

Related

Magic square code loop

This is the code for a method which creates a magic square. n is the length of the square. It has to look like:
static int[][] magicSquare(int n) {
int[][] square=new int[n][n];
I don't understand this k=(k+1)%n; especially, why is it %n ?? Doesn´t that put k to 1 every loop again?
for (int i=0; i<n; i++){
in k=i;
for (int j=0; j<n; j++){
square[i][j]=k+1;
k=(k+1)%n;
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
The % in Java is used for modular division. Whenever the operator is applied the right-hand operand will be subtracted as many times as it can from the left-hand operand and what's left will be the output. You can easily check it by dividing the left-hand operand by the right-hand operand and take the leftover as an integer. In the case of a%b it will be like
a - (a/b)*b.
here are some examples:
10 % 4 = 2 // 2*4 = 8 + 2 = 10
10 % 5 = 0 // 2*5 = 10 + 0 = 10
0 % 4 = 0 // result here is 0 thus 0*4 = 0 + 0 = 0
// if you try to extract 4 from 0, you will not succeed and what's left will be returned (which was originally 0 and it's still 0)...
In your case:
k = (k + 1) % n;
is assuring that the value of k will never exceed 4, thus if it is dividable by 4 then it will be divided and the leftover will be written there. In the case when k is exactly 4 you will have the value of 0 written down into k but since you are always adding k + 1 it is writing the value of 1.
For beginners I do recommend to print the values you are interested in and observe how do the data migrate. Here I've added some printlns for you just to get the idea. Run the code and test it yourself. I do believe the things are going to be a bit cleaner.
public static void main(String[] args) {
int n = 4;
int[][] square = new int[n][n];
System.out.println("--------------");
for (int i = 0; i < n; i++) {
int k = i;
System.out.println("Filling magic cube line " + (i + 1) + ". The k variable will start from " + i + "."); // i initial value is 0 so we add 1 to it just to get the proper line number.
for (int j = 0; j < n; j++) {
System.out.println("Filling array index [" + i + "][" + j + "] = " + (k + 1)); // array indexes start from 0 aways and end at array.length - 1, so in case of n = 4, last index in array is 3.
square[i][j] = k + 1; // add 1 to k so the value will be normalized (no 0 entry and last entry should be equal to n).
k = (k + 1) % n; // reset k if it exceeds n value.
}
System.out.println("--------------");
}
Arrays.stream(square).forEach(innerArray -> {
Arrays.stream(innerArray).forEach(System.out::print);
System.out.println();
});
}
You could always play around and refactor the code as follows:
public static void main(String[] args) {
int n = 4;
int[][] square = new int[n][n];
System.out.println("--------------");
for (int i = 1; i <= n; i++) {
int k = i;
System.out.println("Filling magic cube line " + i + ". The k variable will start from " + i + ".");
for (int j = 0; j < n; j++) {
System.out.println("Filling array index [" + (i - 1) + "][" + (j - 1) + "] = " + k); // array indexes start from 0 aways and end at array.length - 1, so in case of n = 4, last index in array is 3. Subtract both i and j with 1 to get the proper array indexes.
square[i - 1][j - 1] = k;
k = (k + 1) % n; // reset k if it exceeds n value.
}
System.out.println("--------------");
}
Arrays.stream(square).forEach(innerArray -> {
Arrays.stream(innerArray).forEach(System.out::print);
System.out.println();
});
}
Remember that the array's indexing starts from 0 and ends at length - 1. In the case of 4, the first index is 0 and the last one is 3. Here is the diff of two implementations, try to see how does the indexes and values depends both on the control variables i and j.
https://www.diffchecker.com/x5lIWi4A
In the first case i and j both start from 0 and are growing till they it's values are both less than n, and in the second example they start from 1 and are growing till they are equal to n. I hope it's getting clearer now. Cheers

Running Time of this Simple Program - Time Complexity

I am trying to figure out what the time complexity of this simple program is, but I can't seem to understand what would be the best way to do this.
I have written down the time complexity side by side for each line
1 public int fnA (int n) {
2 int sum = 0; O(1)
3 for (int i = 0; i < n; i++) { O(n)
4 int j = i; O(n)
5 int product = 1; O(1)
6
7 while (j > 1) { O(n)
8 product ∗= j; O(log n)
9 j = j / 2; O(log n)
10 }
11 sum += product; O(1)
12 }
13 return sum; O(1)
14 }
Am I correct to assume these running times and that the final running time is: O(n)
If not, would somebody be able to explain where it is I am going wrong?
Overall:
1 + n + n + 1 + n + logn + logn + 1 + 1
= 3n + 2logn + 4
Final: O(n)
Time complexity for that algorithm is O(NlogN).
The for loop is executed N times (from 0 to N).
The while loop is executed logN times since your are dividing the number to half each time.
Since your are executing the while inside the for, your are executing a logN operation N times, from there it is the O(NlogN).
All remaining operations (assign, multiplication, division, sum) you can assume that takes O(1)
The crux of the above program is the while loop and it is the defining factor and rest of the lines will not have complexity more than O(n) and assuming that arithmetic operations will run in O(1) time.
while (j > 1) {
product ∗= j;
j = j / 2;
}
The above loop will have a run time of O(log(j)) and j is varying from 1 to n, so its the series...
-> O(log(1) + log(2) + log(3) + log(4).....log(n))
-> O(log(1*2*3*4...*n))
-> O(log(n!))
and O(log(n!)) is equal to O(n log(n))
For the proof for above refer this
No for every i, there is logn loop running and hence for n elements the total complexity is nlogn.
Since you know that the following loop takes logn .
while (j > 1) {
product ∗= j;
j = j / 2;
}
Now this particular loop is executed for every i. And so this will be executed n times. So it becomes nlogn.
To start with, you could count all operations. For example:
1 public int fnA (int n) {
2 int sum = 0; 1
3 for (int i = 0; i < n; i++) {
4 int j = i; n
5 int product = 1; n
6
7 while (j > 1) {
8 product ∗= j; ?
9 j = j / 2; ?
10 }
11 sum += product; n
12 }
13 return sum; 1
14 }
Now we could do the counting: which sums up to: 2 + 3n + nlog(n)
In a lot of programs the counting is more complex and usually has one outstanding higher order term, for example: 2+3n+2n2. When talking about performance we really care about when n is large, because when n is small, the sum is small anyway. When n is large, higher order term drawf the rest, so in this example 2n2 is really the term that matters. So that's the concept of tilde approximation.
With that in mind, usually one could quickly identify the portion of code that gets executed most often and use its count to represent overall time complexity. In example given by OP, it would look like this:
for (int i = 0; i < n; i++) {
for (int j = i; j > 1; j /= 2)
product *= j;
}
which gives ∑log2n. Usually the counting involves discrete mathamatics, one trick I have learned is to just replace with it integral and do caculus: ∫ log2n = nlog(n)

Finding a Prime Numbers

I have an array of length N=10^5 For each index 1<=i<=n I have to calculate the difference between A[j]-A[i] and (j-i) is prime and j>i
Here is my code:
for(int i=1;i<=n;i++){
for(int j=0;j<prime.size();j++){
int x = prime.get(j);
if(x+i>n) break;
ans+= A[x+i]-A[i];
}
}
How should i make this work even faster ? I think the time complexity is O(N*prime.size)
First, I will rephrase your question so that it states what I believe you want to achieve. You are probably looking for the sum of the differences of the form A[j]-A[i], where (j-i) is a "positive" prime and 1<=i<j<=N. With this statement in mind...
We count the number of times A[k] is added to the sum (denoted by p) and the number of times A[k] is subtracted from the sum (denoted by m). Well, m is equal to the number of primes in the interval [1,N-k], while p is equal to the number of primes in the interval [1,k-1]. If you don't believe me, simulate step-by-step what your code does. Then you can do:
S = 0
for k = 1 to N do
S = S + (p(k) - m(k)) * A[k]
endfor
Now, we need to find a way to determine p and m efficiently for each k in the interval [1,N]. I see you have already constructed what seems to be an ordered list of primes. So, to answer a query of the form 'how many primes in the interval [1,t]?' you could perform a binary search on that list for t. This would get the complexity down to O(N*log(prime.size)).
As an alternative, you can pre-compute the answers to the queries of the form 'how many primes in the interval [1,t]?'. You need an extra array nrPrimesLessThan of size N to keep the results, doing something like this to compute its values:
count = 0
for i = 1 to N do
if i < prime.get(count) then
nrPrimesLessThan[i] = count
else
count = count + 1
nrPrimesLessThan[i] = count
endif
endfor
The pre-computation part takes O(N) steps, but now one query takes O(1) steps, thus the calculating the sum takes O(N) steps. Overall, linear time in N.
Judging from your code example, you want to sum the differences of all value pairs in the array for which the difference of the indices is prime. You've got already an array of primes.
The diagram below shows how the elements get subtracted and added:
0 1 2 3 4 5 6 7 8 9
- + + + + 0
- + + + + 1
- + + + + 2
- + + + 3
- + + + 4
- + + 5
- + + 6
- + 7
- 8
- 9
A + means an element is added to the overall sum. A - means the element is subtracted from the sum. This is not a single subtraction; the subtraction happens for each addition to its left, so A[0] is subtracted 4 times. It is never added.
On the other hand, A[9] is never subtracted, but added four times. In general, each element is subtracted as many times as there are plusses in a row and it is added as many times as there are plusses in a columns. There is a symmetry here:
add[i] = sub[N - i - 1]
for zero-based indices. What is the value of add[i]? It is the number of primes that are smaller or equal to i.
Here's a code example where the add array is called m:
int psum2(const int A[], int n)
{
int sum = 0;
int m[n];
int j = 0;
int k = 0;
for (int i = 0; i < n; i++) {
if (i == prime[j]) {
k++;
j++;
}
m[i] = k;
}
for (int i = 0; i < n; i++) {
sum += (m[i] - m[n - i - 1]) * A[i];
}
return sum;
}
The array m is always the same and can be precalculated if you need to perform the sum more often. The algorithm is O(n).
The problem is also unrelated to primes at its core. The method above works for all conditional sums of differences where the difference of the indices must be conteined in a certain set of numbers.

Iteration expression i += i

I have just started learning Java and pretty much programming and saw the following for loop expression:
for (int i = 1; i < 100; i += i)
System.out.print(i + " ");
My understanding is that "i += i" is short for "i = i + i". The output of the loop is "1, 2, 4, 8, 16, 32, 64". Cannot get my head around the iteration when "i" is 3 and higher. How can it become 8 etc.?
Because it's
Iteration 1 => 1+1
Iteration 2 => 2+2
Iteration 3 => 4+4
Iteration 4 => 8+8
etc.
With this particular for loop, the print statement is not being executed when i is 3 because i increments from 2 to 4. Let's take a closer look:
for (int i = 1; i < 100; i += i)
// iteration 1
System.out.print(i + " ");// prints 1 increment (1 += 1) == 2
------------------------------------------------------------------
// iteration 2
System.out.print(i + " ");// prints 2 increment (2 += 2) == 4
------------------------------------------------------------------
// iteration 3
System.out.print(i + " ");// prints 4 increment (4 += 4) == 8
------------------------------------------------------------------
// iteration 4
System.out.print(i + " ");// prints 8 increment (8 += 8) == 16
------------------------------------------------------------------
As you can see, i becomes 8 because on the third iteration of the loop, i is 4 and increments by itself to become 8.
Hope it helps :-)
first increment time : 1 + 1 = 2
second time : 2 + 2 = 4
third time : 4 + 4 = 8
forth time : 8 + 8 = 16 ... and so on 32,64,128,256....
Hope this helps you to clear your doubt.
In expression x+=y means really that you are writing x=x+y. In your expression i+=i really means that you are writing i = i+i which is equivalent to i = 2*i.
Now how for is working...It's calculating int i = 1 only once. Then it's checking your loop condition i < 100. The next step is to calculate next iteration value which will be i = 1 + 1 =2.
The 3rd iteration will calculate value for i in such way - i = 2 + 2 =4.
The 4rd iteration will be i = 4 +4 =8
....
If you want just to add by one, then please change i +=i by ++i.
for (int i = 1; i < 100; i += i)
System.out.print(i + " ");
Equivalent to:
int i = 1;
while(i<100){
System.out.print(i + " ");
i +=i;
}
Just to for completeness: i += K; is not exactly i = i + K; It is i = (TypeOf i ) (i + k)

Logarithmic and other for loop converted to sum notation

I need help with for loops converted to a sum nations. Some of are easy but others are a bit tricky. I need getting the sum notation setup correctly.
Like this: (Correct for example loop)
As an example:
for (int i = 0; i < n; i = i + 1)
a = i; //cost 1
Sum 1, i=0 to n-1 == n.
I need help with following:
Logarithmic (just the correct sum notation)
for (int i = 0; i < n; i = 2 * i)
a = i; //cost 1
Sum 1, i=0 to log(n)-1 == log n. Correct??
Triple nested (both sum notation and step by step why it ends up like it)
for (int i = 0; i < n; i = i + 1)
for (int j = 0; j <= i; j = j + 1)
for (int k = 0; k <= j; k = k + 1)
a=i; //cost 1
The triple nested loop
I'll give a simple, but a very useful method to analyze such summations in terms of the asymptotic notation.
This is a very general method, you can use it to bound many multiple index summations without a big effort.
Upper bound
First of all, let's derive an upper bound for the sum. It's quite easy:
Lower bound
The trick in this case is to derive the lower bound. The rule of thumb is to reduce the summation range incrementing the lower summation index to the fraction of the upper index and then substitute the new lower index as the upper index in the nested loop. It's also pretty easy:
Putting it together
From both inequalities, you can deduce that:
Which in terms of the asymptotic analysis gives:
As you can see, your triple nested loop has the same asymptotic time complexity as:
for(int i = 0; i < n; i = i + 1)
for(int j = 0; j < n; j = j + 1)
for(int k = 0; k < n; k = k + 1)
//operations of cost 1
For the logarithmic loop:
First, you can't initialize the index with zero when dealing with logarithmic loops.
Second, the following is the way to present the algorithmic loop using Sigma notation:
Look at the last slide of this document of Dr. Jauhar.
For the three nested loops:
Mark Allen Weiss work may help you considerably. See this link.
Logarithmic
The second for-loop will never stop (0 * 2 = 0). I guess, you were asking about this loop:
for (int i = 1; i < n; i = 2 * i)
a = i; //cost 1
In this case the complexity expressed via the sum notation will be:
Sum 1, i=1 to log(n-1) == O(log n)
Triple nested
In this case it will be the summation of:
number of steps sum
--------------------------------------
1 1 1 1 1 1 . n
2 2 2 2 2 . 2(n-1)
3 3 3 3 . 3(n-2)
4 4 4 . 4(n-3)
. . . .
n-1 n-1 2(n-1)
n n
or alternatively if I transpose the triangle:
number of steps sum
--------------------------------------
1 2 3 4 . n-1 n n(n+1)/2
1 2 3 4 . n-1 (n-1)(n)/2
1 2 3 4 . (n-2)(n-1)/2
1 2 3 . 4(n-3)
1 2 . .
1 . 3
. 1
The numbers on the right side (in the second triangle) are also called triangle numbers. So the question is equivalent to
"What is the sum of triangle numbers lower or equal than f(n). (f(1) + f(2) + f(n), where f(x) = x(x+1)/2)."
The answer to this question is
f(n) = n(n+1)(n+2)/6
The proof is here.
So the resulting complexity in big-o is O(n^3)

Categories

Resources