Within a class Main that attempts to find the last digit of a factorial val, why does
public static void main(String[] args) {
int testcases = sc.nextInt();
for (int i = 0; i < testcases; i++) {
int result = 0;
int val = sc.nextInt();
if (val < 3) {
result = val;
} else {
for (int j = 1; j <= val; j--) {
result *= j;
result %= 10;
}
}
System.out.println(result);
}
}
Take so much longer to compute than the same code except for the difference in this snippet:
for (int j = 1; j <= val; j++) {
result *= j;
result %= 10;
}
I'm aware the second iteration does not provide the right answer, I am curious though as to why it takes so much longer to compute the second as opposed to the first loop.
What the loop code is doing
For loops run a block of code multiple times based on 3 conditions:
The starting value of the loop variable (in your case int j = 1)
The condition in which the loop continues (in your case j <= val - So it will stop once j becomes greater than or equal to val
The way that the loop variable changes with each iteration (in your case either j-- or j++
j-- is the decrement operator. It is the same thing as j = j - 1. j++ on the other hand is the increment operator. It is the same thing as j = j + 1
This means that the loop for (int j = 1; j <= val; j--) will run the block of code with j = 1 and then decrement the value of j. It does this as long as j is less than or equal to val. On the other hand, the loop for (int j = 1; j <= val; j++) runs the block of code and then increments the value of j, which it will do as long as j is less than or equal to val.
So, for j-- the sequence of j values that you have is 1,0,-1,-2... while the sequence of values you have for j++ is 1,2,3,4...
An example run
Let's take an example where val is 10. With j++ your loop will run for 1,2,3,4,5,6,7,8,9,10 and then stop, so it runs 10 iterations. With j-- it will run for 1,0,-1,-2,-3.... As you can see, these values are getting further away from 10, which is the value where the loop will stop. What happens is that the loop just keeps running until your integer overflows. When you get to the lowest possible value of an int, the next iteration of decrementing causes the sign of the number to flip and j become the largest possible integer value, which will be greater than 10 and break the loop. In Java, the standard size of an int is 32 bits, so the smallest integer will be -(2^31-1) which is -2,147,483,648. Therefore, if you run with j--, your loop will run over 2 billion times before stopping which is why it takes so much time to run. .
Related
Here is my solution:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValues = 0;
int maxNum = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++){
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
int absValuesDiff = Math.min(absValues, maxNum);
return absValuesDiff;
}
I pass small test cases, but not ones with a larger data set.
As L_Cleo suggested, you indeed check the minimum value only once.
Instead, you should check it on every iteration of the loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValue = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++) {
absValue = Math.min(absValue, Math.abs(arr.get(i) - arr.get(i + 1)));
}
return absValue;
}
I added the minimum check on every iteration. The checking is done between the absValue and the absolute difference of the current loop iteration.
By the end of the loop, absValue will contain the minimum value, because you have compared it to every other possibility.
The longer explanation why this works is this:
The reason why updating the absValue in each loop iteration is enough is this: absValue's first value is Integer.MAX_VALUE. This means that any other value will be smaller than absValue. In the first loop iteration, absValue is updated with the first absolute difference. In all other iterations, the code will always update absValue with the smaller value between the current absValue and the absolute difference you calculate on each iteration.
This guarantees that, for all iterations, the smallest value will be stored in absValue at some point, and in the further iterations, absValue value will not change.
The problem in your solution is that you're not checking all possible couples within the array of numbers.
With this for loop, for example:
for (int i = 0; i < arr.size() - 1; i++) {
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
And iterating over the simple array 1, 4, 6, 7, you would be checking the couples [1,4], [4,6] and [6,7], but you're still missing 1,7 and 4,7.
So step number one would be to iterate over the array per every number of the array (knowing that the order of the pairs doesn't matter [1,6] == [6,1] in this case, you will have to check 1 less number every iteration of the outer loop... here is an example of a correct for loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
Collections.sort(arr);
int minAbsoluteValue = Integer.MAX_VALUE;
for(int i=0; i < arr.size() - 1; i++) {
for(int j=i+1; j < arr.size(); j++)
minAbsoluteValue = Math.min(Math.abs(arr.get(i) - arr.get(j)), minAbsoluteValue);
}
return minAbsoluteValue;
}
As you can see, another missing part in your solution is the tracking of the minimum value. You're checking the minimum value between the last iterated couple and the maxInteger value only once, while you have to that for every couple.
This might not be the most efficient solution...
Let's say I have number x=6 I want to divide this number in such a way that I can run 3 loops based on the 1st, 2nd and 3rd part.
For example: x=6 then 1st loop (1-2), 2nd loop (3-4), 3rd loop (5-6).
Example 2: x=3000 then 1st loop (1-1000), 2nd loop (1001-2000), 3rd loop (2001-3000). I don't want to put manually because x can be any "even" number.
x will be number that can be equally divided like 3,6,9,12,15,18 .....
You can do this by the following code. There is no validation as you said the number would be divisible
int x; //your value
int step = x/3;
for(int i=0;i<3;i++){
for(int j=(step*i)+1;j<=step*(i+1);j++){
//do something with j
}
}
This will run the the inner loop 3 times and the inner loop will run x/3 times.
public static void executeLoop(int multiple) {
int interval = multiple / 3;
int start = 0;
int end = 0;
for (int i = 0; i < 3; i++) {
start = i * interval;
end = start + interval;
for (int j = start; j < end; j++) {
System.out.printf("i: %d, j: %d\n", i, j);
}
}
}
I understand the principle of recursion and code but do not understand the loop for,Why variables are in the same line, we can explain how the loop works?
this line:
for (int i = digit, j = 1; i >= 1; i--, j++)
The code:
public static boolean hasSubSeries(int[] arr, int digit) {
return hasSubSeriesHelper(arr, arr.length, digit);
}
public static boolean hasSubSeriesHelper(int[] arr, int size, int digit) {
if (size == 0)
return false;
for (int i = digit, j = 1; i >= 1; i--, j++) {
if (arr[size - j] != i)
return hasSubSeriesHelper(arr, size - 1, digit);
}
return true;
}
thank's
The structure of the for loop is as follows:
for( starting conditions; verification at each loop; action at end of loop)
In your specific case:
for (int i = digit, j = 1; i >= 1; i--, j++)
Starting conditions:
A variable i which is equal to the value contained in the variable digits that is given at the start of the function hasSubSeriesHelper(int[] arr, int size, int digit).
A variable j which starts at 1.
Verification at each loop:
Once each loop is completed we will check this, if it is True, we keep on looping, if not we exit the loop.
We check to see if i declared at the start is greater than or equal to 1, if it is we keep on looping, if not we stop.
Action at end of loop:
We do two actions i-- which decreases the value of i by 1 and j++ which increases the value of j by 1.
To summarise you could translate it to a while loop if you prefer:
int i = digit;
int j = 1;
while ( i >= 1 ) {
// the code inside the for loop goes here
i--;
j++;
}
Note that the actions at the end happen inside the loop whilst the starting condditions go before the loop.
That should also clarify why you can have various declarations in the same line as long as they are of the same type.
You have three parts in a for loop
N°1 : Initialization of variable(s)
N°2 : Boolean expression evaluated to continue/stop looping
N°3 : Changes operated on variables
1
You may have multiple initialization in the first part, as long as the type stay the same, the following is entirely possible :
We declare and instantiate three variables within the first part of our for declaration.
for(int i = 2, j = 2*i, k = 4*j ; i < 3 ; i++) {
System.out.println(i + " " + j + " " + k); // 2 4 16
}
I have the following code from a previous past paper:
int n = arr.length;
double min = 0;
int minLocation=0;
for(int i = 1; i <= n; i++) {
if( arr[i] < min ) {
min = arr[i];
}
minLocation = i;
}
System.out.print("The minimal value is arr[");
System.out.println(minLocation + "] = " + min);
I have to answer the following questions from the code:
(i) The line on which the error appears
(ii) What effect the error would have
(iii) How the error should be corrected.
You may assume arr[] is a non-empty array of double values that has been
properly declared and initialized.
I know there will be a runtime error at the line with the if statement which i'm still not sure how. As I am unable to correct it I can't see how I get the undesired results. I can see it's such a straight forward question and I am missing out something extremely obvious but I have been looking at it for a while and i'm completely missing it.
There are several mistakes in that code. Here a list of them including explanation of impact and how to fix them:
You are initialising min with 0
Effect: If your array e.g. only consists of {1.1, 2.2} your code would claim that 0 is the minimum, what obviously is wrong because there doesn't exist an index i that arr[i] == 0
Fix: double min = Double.MAX_VALUE;
Your for-loop starts at index 1 for (int i = 1; ...)
Effect: You are skipping arr[0]
Fix: for (int i = 0 ...)
Your loop iterates once to often because of the condition or ( ... ; <= n; ...)
Effect: You will encounter an AIOOBE (ArrayIndexOutOfBoundsException)
Fix: for ( ... ; i < n; ...)
Your are overwriting minLocation in every iteration of the loop
Effect: After the last iteration of the loop, minLocation will always be = n
Fix: Place minLocation = i; inside the if-statement.
Corrected version
int n = arr.length;
double min = Double.MAX_VALUE;
int minLocation = 0;
for(int i = 0; i < n; i++) {
if(arr[i] < min) {
min = arr[i];
minLocation = i;
}
}
I know there will be a runtime error at the line with the if statement
which i'm still not sure how
This runtime error will be IndexOutOfBoundsException. This error occur because array index is one less than array size.
Your loop should be like.
for(int i = 0; i < n; i++)
Did you intend your for() loop to start at index 1? By convention it starts at 0;
It should really be: for(int i=0;i
Your for loop needs to be:
for(int i = 0; i < n; i++)
Otherwise you will get an IndexOutOfBoundsException since you access the array outside of its range.
Also you should change your min value initialiaztion to:
double min = Double.MAX_VALUE;
Otherwise you will only find the minimum if your array only contains negative values.
There are logical errors in your program, if it is intended to find the minimal value and position of given array.
Initialize
double min = arr[0];
End for loop at
i < n
Include
minLocation = i;
as
if( arr[i] < min )
{
min = arr[i];
minLocation = i;
}
Java array indices start at 0. So the for loop should be for( int i = 0; i < n; i++ ).
The minimum is only computed if the the elements of the array are non-negative.
Suppose you want to loop from i=0 to i=n and j=0 to j=m and that m!=n. Is it possible to shorten the following two loops into one?
for(int i=0; i<=n; i++){}
for(int j=0; j<=m; j++){}
To something along
for(int i=0,j=0; i<=n, j<=m; i++, j++){}
In essence I want the loop to say "increment both i and j by one, stop incrementing i if i=n but keep incrementing j if m>n" or the other way around if n>m.
May seem trivial or stupid but I am curious.
Naively, we want to do something like:
for(int i = 0, j = 0; i <= n || j <= m; i = Math.min(n, i+1), j = Math.min(m, j+1))
...but this won't terminate, because the maximum value for i is n and the maximum value for j is m, and one of those will always be true.
The problem is much simpler if you're willing to let (for n < m) i finish at n+1, as we could write:
for(int i = 0, j = 0; i <= n || j <= m; i = Math.min(n+1, i+1), j = Math.min(m+1, j+1))
This is complicated only if you want to keep (for n < m) i = n while j finishes incrementing. The complexity is isolated to getting the loop to terminate at the right time, while still allowing j to finish incrementing.
To get the loop to terminate, we want to increment the larger number one step past its maximum, so that we hit the termination criteria. Since we know at least one of i <= n and j <= m will always be true, let's focus on making both always true, and change our termination criteria to
i <= n && j <= m
In the case where n < m, i will finish incrementing before j, and so we need to let j increment one past its effective maximum in order to violate i <= n && j <= m. A similar condition holds for n > m, but instead, we need to increment i one past n.
Notice, though, that if n == m, we can safely increment both one past their respective limits, and the termination criteria will hit at the same time. The loop below handles any positive input n or m and terminates correctly given your conditons, while allowing the lesser of n or m to become the maximum value for the respective iterator.
for(int i = 0, j = 0, nadj = n + (n >= m ? 1 : 0), madj = m + (m >= n ? 1 : 0)
i <= n && j <= m;
i = Math.min(nadj, i+1), j = Math.min(madj, j+1))
Worth noting, we compute nadj and madj in the first section to avoid recomputing them during every iteration.
Edit
for(int i=0,j=0; i+1<=n || j+1<=m; ){
if(i<n) i++;
if(j<m) j++;
// do stuff here
// keep in mind that i and j starts from 1
}
Fiddle: http://jsfiddle.net/nilgundag/4frCG/
Old Answer:
for(int i=0,j=0; i<=n || j<=m; ){
if(i<=n) i++;
if(j<=m) j++;
// do stuff here
// keep in mind that i and j starts from 1
}
You can use only one iterator i since you increment i and j by 1 every time.
for(int i=0; i<=n || i<=m;i++ ){
if(i<=n) //{do first loop job}
if(i<=m) //{do second loop job}
}
C++:
for (int i=0, j=0; j<=m || i<=n; i+=i<=n, j+=j<=m ){}
JAVA:
for (int i=0, j=0; j<=m || i<=n; i+=(i<=n)?1:0, j+=(j<=m)?1:0 ){}