Java output reply so slow - java

i'm doing a exercise about a snail that climb a wall and i have to calculate how manys days it would take to reach the top, i already did my algorithm and it give me the expected output but it takes so long in a input case, basically what code have to do is given N M T N=how manys meter he climb a day M= how manys meters he fall in the night and T= what's the lenght of the wall this is my code any help will be useful this is my code PD it already work but it's too slow
int distance=0;
int[] up = { 2, 5 ,100};
int[] down= { 1,1 ,99};
int[] Top = {5,6 ,1000000000};
int days = 0;
for (int i = 0; i < up.length; )
{
distance += up[i];
if (Top[i] <= distance)
{
days++;
System.out.println(days);
i++;
days = 0;
distance = 0;
}
else
{
distance -= down[i];
days++;
}
}
the output are the next : case 1: 4
case 2: 2
case 3 :999999901

Your code can be refactored to simplify it. This is how Wikipedia describes refactoring:
Code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements.
So we're going to apply a set of micro-refactorings.
First, the two statements inside the else clause can be flipped.
} else {
days++; // Statement moved up
distance -= down[i];
}
When you do that, both the if block and the else block starts with days++;, so it can be moved outside.
for (int i = 0; i < up.length;) {
distance += up[i];
days++; // Statement moved outside
if (Top[i] <= distance) {
System.out.println(days);
i++;
days = 0;
distance = 0;
} else {
distance -= down[i];
}
}
Since the for loop doesn't modify i, it behaves like a forever-loop, as long as code inside the loop doesn't change i. So, we can add a forever-loop and break out of it when we change i. The effect is that nothing has changed, but it prepares for the next set of refactorings.
for (int i = 0; i < up.length;) {
for (;;) { // Forever-loop
distance += up[i];
days++;
if (Top[i] <= distance) {
System.out.println(days);
i++;
days = 0;
distance = 0;
break; // Break out, since we changed i
} else {
distance -= down[i];
}
}
}
Since the break statement is the only way to exit the forever-loop, we can move the code that is before the break to outside (i.e. after) the loop.
int distance = 0;
int days = 0;
for (int i = 0; i < up.length;) {
for (;;) {
distance += up[i];
days++;
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
}
System.out.println(days); // Moved outside forever-loop
i++; // Moved outside forever-loop
days = 0; // Moved outside forever-loop
distance = 0; // Moved outside forever-loop
}
Since days and distance are initialized to 0 before the outer loop, and reinitialized to 0 at the end of the loop, we can just do that at the start of the loop instead, and we can then declare them there. We can also move the i++ to the for loop.
for (int i = 0; i < up.length; i++) { // i++ moved here
int distance = 0; // Moved to top of loop and declared here
int days = 0; // Moved to top of loop and declared here
for (;;) {
distance += up[i];
days++;
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
}
System.out.println(days);
}
We will now do the opposite operation for the two statements that increment distance and days inside the forever-loop, i.e. do those two statement both before the loop, and at the end of the loop.
for (int i = 0; i < up.length; i++) {
int distance = 0;
int days = 0;
distance += up[i]; // Moved here
days++; // Moved here
for (;;) {
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
distance += up[i]; // Also moved here
days++; // Also moved here
}
System.out.println(days);
}
The initialization of distance and days can be combined with the incrementing done before the forever-loop. Also, since the break exits the loop, there is no need for else anymore.
for (int i = 0; i < up.length; i++) {
int distance = up[i]; // Combined =0 with +=up[i]
int days = 1; // Combined =0 with ++
for (;;) {
if (Top[i] <= distance)
break;
distance -= down[i]; // else clause eliminated
distance += up[i];
days++;
}
System.out.println(days);
}
distance is only used inside the forever loop, so we can move the declaration to the loop. The update of distance can be moved to the 3rd part of the forever loop. The if statement is at the top of the forever-loop, so it can become the loop condition instead, changing the forever-loop to a regular for loop.
for (int i = 0; i < up.length; i++) {
int days = 1;
for (int distance = up[i]; distance < Top[i]; distance += up[i] - down[i]) {
days++;
}
System.out.println(days);
}
See how much simpler your code is now, and we never changed the logic of the code. We just moved it around, i.e. refactored it.
Your performance issue is caused by the inner loop having to iterate almost a billion times for the 3rd use-case, but now that we can see a simple for loop, we can actually calculate how many times it will iterate.
To build that formula, consider a normal loop.
for (int value = start; value < stop; value += step)
How many times will that iterate? It will have to add step a total of x times until value reaches stop, so that means x = (stop - start) / step.
If stop - start is not an exact multiple of step, we need to make sure we always round up, so value will be >= stop. Using integer math, you do that by adding step - 1 before dividing, since integer division will truncate the result, leading to this formula: x = (stop - start + step - 1) / step
Applying that to our loop, we get:
x = (stop - start + step - 1) / step
x = (Top[i] - up[i] + (up[i] - down[i]) - 1) / (up[i] - down[i])
x = (Top[i] - down[i] - 1) / (up[i] - down[i])
days = 1 + x
days = 1 + (Top[i] - down[i] - 1) / (up[i] - down[i])
Since there is no need to assign result to a variable days anymore, your code becomes:
int[] up = { 2, 5, 100 };
int[] down = { 1, 1, 99 };
int[] Top = { 5, 6, 1000000000 };
for (int i = 0; i < up.length; i++)
System.out.println(1 + (Top[i] - down[i] - 1) / (up[i] - down[i]));
Output
4
2
999999901
Result is instantly calculated. No delays.

You can use a little maths to come up with a closed formula:
Math.ceil(((double)top - down) / (up - down))

Related

Java Sudoku brute force solver, how does it work?

So you find the code below here. Most of the code I understand, but there is one bit I don't. The place where we create the boolean array called digits and the bit after that 3 * (x / 3).
I think it's used to check if each square in the sudoku has 9 unique numbers as well, but I'm not sure on how I can explain this to let's say someone next to me.
Why do I need the array of boolean here? Can someone explain to me what it is doing and why?
Kind regards!
public int[][] solvePuzzle(int[][] matrix) {
int x, y = 0;
boolean found = false;
// First we check if the matrix contains any zeros.
// If it does we break out of the for loop and continue to solving the puzzle.
for (x = 0; x < 9; x++) {
for (y = 0; y < 9; y++) {
if (matrix[x][y] == 0) {
found = true;
break;
}
}
if (found) {
break;
}
}
// If the puzzle doesn't contain any zeros we return the matrix
// We now know that this is the solved version of the puzzle
if (!found) {
return matrix;
}
boolean digits[] = new boolean[11];
for (int i = 0; i < 9; i++) {
digits[matrix[x][i]] = true;
digits[matrix[i][y]] = true;
}
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
digits[matrix[boxX + i][boxY + j]] = true;
}
}
// We loop over all the numbers we have to check if the next number fits in the puzzle
// We update the matrix and check recursively by calling the same function again to check if the puzzle is correct
// If it's not correct we reset the matrix field to 0 and continue with the next number in the for loop
for (int i = 1; i <= 9; i++) {
if (!digits[i]) {
matrix[x][y] = i;
if (solvePuzzle(matrix) != null) {
return matrix;
}
matrix[x][y] = 0;
}
}
// The puzzle can't be solved so we return null
return null;
}
I have added some explanation as comments inline:
//we need to know what digits are we still allowed to use
//(not used in this row, not used in this column, not used in
//the same 3x3 "sub-box")
boolean digits[] = new boolean[11];
//so we run through the rows/coumns around the place (x,y)
//we want to fill in this iteration
for (int i = 0; i < 9; i++) {
//take a used number from the row of x (matrix[x][i]) and mark it
// as used
digits[matrix[x][i]] = true;
//take a used number from the column of y (matrix[i][y]) and mark it
// as used
digits[matrix[i][y]] = true;
}
//find the top-left corner of the sub-box for the position (x,y) we
//want to fill in
//example: x is 8 -> 3 * 8/3 -> 6, so we start from 6
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
//iterate through the sub-box horizontally and vertically
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//take a used number from the sub-box and mark it
// as used
digits[matrix[boxX + i][boxY + j]] = true;
}
}
There seem to be two issues you are unclear on:
The boolean array - this array is used to track which digits have been used already on a specific row or column. So imagine a row of tick boxes each with a digit written next to it (the array index) - these boxes are checked or unchecked to show a digit has been used or not.
The expressions 3* (x/3) and 3 * (y/3) - what you need to remember here is that this is integer division (that means the result of the division is always rounded down to an integer. For example if x=1 then 3 (x/3) is 3 (1/3) is 3 * (0) =0 (whereas if this was float division the result would be 3*(0.3333)=1. So these maths expressions essentially change you number to the next lowest multiple of three - that is 1 -> 0, 2 -> 0, 3 -> 3, 4 -> 3 etc.

ArithmeticException division by zero... how to fix this method?

The purpose of this method is to iterate through a 2D array of integers called grid[][], and translate the integers based on the maximum and minimum values into a smaller range between 100 and 250 (the original minimum value becomes 100, the original maximum value becomes 250, and everything in between is calculated respectively). When this method is called, division by zero ArithmeticException occurs.
Clearly I'm making some logic mistakes here... I just don't see the fix. Can anyone help?
public int greenValues(int arrayVal) {
int max = 0;
int min = 0;
int colorValue = 0;
int temp;
for (int i = 0; i < grid.length; i++) { // finds maximum and minimum numbers in file
for (int j = 0; j < grid.length; j++) {
if (max < grid[i][j]) {
max = grid[i][j];
}
if (min > grid[i][j]) {
min = grid[i][j];
}
}
}
int arrayRange = (max-min); // arrayVal, arrayRange, and max and min are 0
temp = (((arrayVal-min) * COLOR_RANGE) / arrayRange) + 100; // map values to range of 100 - 250
colorValue = temp;
return colorValue;
}
This line is culprint for producing ArithmaticExcpetion.
temp = (((arrayVal-min) * COLOR_RANGE) / arrayRange) + 100;
your calculating arrayRange dynamically as you don't know when that value will be 0. so you can wrap this line with try catch block to do some exception handling.
Solution by Dilip is perfect. Or you can also add a conditional statement which lets it pass only when arrayRange is not 0 & execute something else if it is 0. But it'll increase overhead by executing the conditional statement every time arrayRange is calculated.

What is the correct way of implementing the heapsort?

I spend last 5 hours looking at so many videos and readings (cormen included) and i finally decided to write my own heapsort to test it out. I am basically taking some inputs from standard input and storing them in an array and then i will use heapsort to sort them.
Following is my code
public static void buildHeap(int[] A)
{
n = A.length - 1;
for(int i = n/2; i>0; i--)
{
maxHeapify(A,i);
}
}
public static void maxHeapify(int[] A, int i)
{
int left = 2*i;
int right = 2*i + 1;
int largest = 0;
if(left <= n && A[left] > A[i])
{
largest=left;
}
else
{
largest=i;
}
if(right <= n && A[right] > A[largest]){
largest=right;
}
if(largest!=i){
int temp = A[i];
A[i] = A[largest];
A[largest] = temp;
maxHeapify(A, largest);
}
}
My Array Input is : 3,5,8,7,1,13,11,15,6 Output is:
3,15,13,11,6,8,5,7,1
The output is obviously wrong as the first index should contain the highest value 15.
So then i decided to take the good old route of taking a pen and a notebook and tracing the code and realized that in the buildHeap the i should be n-1/2 . However it also did not give me the correct output. I am really lost now and frustrated. Can anyone shed light as to what i am doing wrong?
Your index calculations are off:
int left = 2*i;
int right = 2*i + 1;
If i is 0, then we want left and right to be 1 and 2. If i is 1, then left and right should be 3 and 4, and so on. The calculations should be:
int left = 2*i + 1;
int right = 2*i + 2;
Also,
for(int i = n/2; i>0; i--)
The condition is i > 0. The body of the loop will only run when i > 0, so the element at index 0 (i.e. the first one) won't get moved. The condition should be i >= 0.

Need help reducing triple for loop to increase efficiency

for (int i = 0; i < 3; ++i) {
for (int k = 0; k < 7; ++k) {
for (int h = i; h < 4 + i; ++h) {
result = state.getAt(k, h);
if (result == 1) {
++firstpl;
}
if (result == 2) {
++secondpl;
}
if (firstpl > 0 && secondpl > 0) {
break;
}
//y = k;
}
if (firstpl == 0 && secondpl == 0) {
break;
} else if (firstpl > secondpl) {
score += firstpl * firstpl;
//if(state.getHeightAt(y)-3 < 3) score += 3+firstpl*2;
} else {
score -= secondpl * secondpl;
//if(state.getHeightAt(y)-3 < 3) score -= 3+secondpl*2;
}
firstpl = 0;
secondpl = 0;
}
}
basically I have a 7 by 6 grid. I am going through 7 columns and looking at every 4 consecutive blocks vertically. Since there is 6 blocks upward. There is 3 four consecutive block for each column. State.getAt(k,h) takes in a x and y and returns a value.
I don't think you can improve on this, unless you can figure out an alternative representation for this "state" that allows this computation to be performed incrementally.
And since you have failed to properly explained what the state or the calculation actually mean, it is difficult for anyone but you to figure out whether an alternative approach is even feasible. (And I for one am not going to attempt to reverse engineer the meaning from your code.)
OK. For Connect4, the win / lose is a line of 4 checkers horizontally, vertically or diagonally in the 7x6 grid. So what you could do is represent the score-state as an array of counters, corresponding to each of the columns, rows and diagonals in which a winning line could be made. (7 + 5 + 4 + 4 = 20 of them => 20 counters) Then construct a static mapping from an (x,y) position to the indexes of lines that pass through that. When you add a checker at point (x,y) you look up the counters and increment them. When you remove a checker ... decrement.
I'm not sure how that relates to your existing scoring function ... but then I don't see how that function relates to a strategy that would win the game. Either way, you could potentially use the approach above to calculate scores incrementally.

finding all prime numbers in a given range

I'm writing this Java program that finds all the prime numbers between a given range. Because I'm dealing with really big numbers my code seems to be not fast enough and gives me a time error. Here is my code, does anyone know to make it faster? Thanks.
import java.util.*;
public class primes2
{
private static Scanner streamReader = new Scanner(System.in);
public static void main(String[] args)
{
int xrange = streamReader.nextInt();
int zrange = streamReader.nextInt();
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
if (checkForPrime[checks])
{
System.out.println(checks);
}
}
}
public static boolean[] Primes(int n)
{
boolean[] isPrime = new boolean[n + 1];
if (n >= 2)
isPrime[2] = true;
for (int i = 3; i <= n; i += 2)
isPrime[i] = true;
for (int i = 3, end = sqrt(n); i <= end; i += 2)
{
if (isPrime[i])
{
for (int j = i * 3; j <= n; j += i << 1)
isPrime[j] = false;
}
}
return isPrime;
}
public static int sqrt(int x)
{
int y = 0;
for (int i = 15; i >= 0; i--)
{
y |= 1 << i;
if (y > 46340 || y * y > x)
y ^= 1 << i;
}
return y;
}
}
You'll get an enormous improvement just by changing this:
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
to this:
boolean[] checkForPrime = Primes(1000000);
for (int checks = xrange; checks <= zrange; checks++)
{
Your current code regenerates the sieve zrange - xrange + 1 times, but you actually only need to generate it once.
The obvious problem is that you're computing the primes up to 1000000 many time (zrange - xrange times). Another is that you dont need to compute the primes up to 1000000, you just need to check to primes up to zrange, so you're wasting time when zrange < 1000000, and getting a buffer overflow when zrange > 1000000.
You can start your inner loop from i*i, i.e. instead of for (int j = i * 3; j <= n; j += i << 1) you can write for (int j = i * i; j <= n; j += i << 1) for a minor speed-up.
Also, you have to be sure that your zrange is not greater than 1000000.
If xrange is much greater than sqrt(zrange), you can also split your sieve array in two, for an offset sieve scheme. The lower array will span from 2 to sqrt(zrange). The upper one will span from xrange to zrange. As you sieve your lower array, as each new prime becomes identified by it, inside your inner loop, in addition to marking the lower array up to its end also sieve the upper array. You will have to calcuate the starting offset for each prime i, and use the same step of 2*i as you do for the lower half. If your range is wider than a few primes, you will get speed advantage (otherwise just trial division by odds will suffice).
Another thing to try is, if evens > 2 are not primes anyway, why represent them in the array and waste half of the space? You can treat each i as representing an odd number, 2*i+1, thus compressing your array in half.
Last simple trick is to eliminate the multiples of 3 in advance as well, by marking ON not just odds (i.e. coprimes with 2), by { ... i+=2; ...}, but only coprimes with 2 and 3, by { ... i+=2; ... i+=4; ... } instead. Also, when marking OFF multiples of primes > 3, use { ... j+=2*i; ... j+=4i; ...} too. E.g., in 5*5, 5*7, 5*9, 5*11, ... you don't need to mark OFF 5*9, if no multiple of 3 was marked ON in the first place.

Categories

Resources