Finding the Shortest Path in a 2D Integer Array Java - java

I am making a snake game where the snake crosses through a 2D int array as its terrain. The values stored in the 2D array represent the time in seconds it takes to cross.
For example,
int[][] MAP = {
{ 1, 1, 1, 2, 2 },
{ 1, 2, 2, 2, 2 },
{ 3, 2, 2, 3, 1 },
{ 1, 1, 3, 2, 1 },
{ 1, 1, 3, 2, 1 }
};
So going from map[0][0] to map[0][4] takes 1 + 1 + 2 + 2 seconds. How would I make an algorithm that would find the shortest possible path for a snake to travel from position map[startX][startY] to map[endX][endY]?
This isn't a homework assignment, I'm just making a game for fun and would like to learn how to do this.

This is one is kinda known problem when discussing "dynamic programming", and even resembles an old post.
Still, I didn't find a solution that also prints the shortest path, so:
public class FastestPathCalculator {
private final int[][] map;
public FastestPathCalculator(int[][] map) {
this.map=map;
}
public static void main(String[] args) {
int[][] map = new int[][]{
{1, 1, 1, 4, 2},
{1, 2, 5, 2, 2},
{3, 2, 2, 3, 1},
{1, 1, 3, 2, 1},
{3, 1, 3, 2, 1}
};
FastestPathCalculator c = new FastestPathCalculator(map);
boolean[] result = c.computeFastestPath(map);
c.printPath(result);
}
Here, the boolean array represents the steps taken from (0,0) to (4,4). A value of TRUE means the step is to the right, FALSE means go down.
In this example, the array has 8 cells.
public boolean[] computeFastestPath(int[][] map) {
int pathLength = map.length + map[0].length - 2;
boolean[] result = new boolean[pathLength];
int[][] mapOfMinimalSums = buildMapOfMinimalSums();
int x = map.length-1;
int y = map[0].length-1;
for (int i = pathLength - 1 ; i >= 0; i--) {
if (x == 0)
result[i] = true;
else if (y == 0)
result[i] = false;
else if (mapOfMinimalSums[x][y] == map[x][y] + mapOfMinimalSums[x][y-1]) {
result[i] = true;
y--;
}
else {
result[i] = false;
x--;
}
}
return result;
}
public void printPath(boolean[] result) {
String[][] newPath = new String[map.length][map[0].length];
int x = 0;
int y = 0;
newPath[x][y] = String.valueOf(map[x][y]);
for (int i = 0 ; i < result.length; i++) {
if (result[i]) {
y++;
} else {
x++;
}
newPath[x][y] = String.valueOf(map[x][y]);
}
for (int i = 0 ; i < map.length; i++) {
for (int j = 0 ; j < map[0].length; j++) {
if (newPath[i][j] == null) {
System.out.print(" , ");
} else {
System.out.print(newPath[i][j] + ", ");
}
}
System.out.println();
}
System.out.println();
}
private int[][] buildMapOfMinimalSums() {
int[][] mapOfSums = new int[map.length][map[0].length];
for (int i = 0 ; i < map.length; i++) {
for (int j = 0 ; j < map[0].length; j++) {
if (i == 0 && j == 0)
mapOfSums[i][j] = map[i][j];
else if (i == 0) {
mapOfSums[i][j] = mapOfSums[i][j - 1] + map[i][j];
}
else if (j == 0)
mapOfSums[i][j] = mapOfSums[i-1][j] + map[i][j];
else
mapOfSums[i][j] = Math.min(mapOfSums[i-1][j], mapOfSums[i][j-1]) + map[i][j];
}
}
return mapOfSums;
}
}

Related

Move all zeroes in a given array to the end and replace each non-zero element with the closest greater value, if any

Looking for the optimised solution for the below problem.
Given an unsorted array, we are required to move all zeroes to the end of the array and at same time find the next closest greater number of each element(non-zero) and return the same element incase if there is no next greater element for an element in the array .
Input = {6,1,5,0,0,3,8,6,4}
Output = {8,3,6,4,8,6,4,0,0}
I tried the below :
public class next_closest_element {
public static void main(String[] arg) {
int[] input = {6, 1, 5, 0, 0, 3, 8, 6, 4};
Stack<Integer> stack = new Stack<Integer>();
int k = 0;
int count = 0;
int last_index_value =input.length-1;
for (int i = 0; i < input.length; i++) {
if (input[i] != 0) {
int j = i + 1;
boolean flag = false;
while (j < input.length && input[i] != 0) {
if (input[j] > input[i]) {
if (stack.empty() || !flag) {
stack.push(input[j]);
flag = true;
j++;
} else if (stack.peek() > input[j]) {
stack.pop();
stack.push(input[j]);
flag = true;
j++;
} else {
j++;
}
} else {
j++;
}
}
if (flag) {
input[k] = stack.peek();
k++;
}
else {
input[k]=input[i];
k++;
}
}
else{
count +=1;
}
}
while(count>0){
input[last_index_value]=0;
last_index_value--;
count--;
}
for (int s :
input) {
System.out.println(s);
}
}
}
First shoveling the zeroes to the right would be one optimisation.
Possibly replacing with next closest greater element I have interpreted as next following element (as you seemed to do, as otherwise the last 4 might have become the overwritten 5).
static int[] f(int[] values) {
// In-situ (in-place) algorithm.
int n = 0; // The count of non-zero values.
for (int i = 0; i < values.length; ++i) {
if (values[i] != 0) {
values[n] = values[i];
++n;
}
}
// Zero the rest:
// (With a second array the remaining values from n upwards would
// already be zero.)
for (int i = n; i < values.length; ++i) {
values[i] = 0;
}
// {6, 1, 5, 0, 0, 3, 8, 6, 4} -> {6, 1, 5, 3, 8, 6, 4, [n] 0, 0}
// (First optimisation.) Now we only need to deal with n non-zero values.
// Search the next (A) closest greatest (B) number, when found substitute.
// Unoptimized:
for (int i = 0; i < n; ++i) {
int ithValue = values[i];
boolean hasClosest = false;
int closest = Integer.MAX_VALUE;
for (int j = i + 1; j < n; ++j) {
int jthValue = values[j];
if (jthValue > ithValue && (!hasClosest || jthValue < closest)) {
closest = jthValue;
hasClosest = true;
values[i] = jthValue;
}
}
}
// {8, 3, 6, 4, 8, 6, 4, 0, 0}
return values;
}
public static void main(String[] args) {
int[] input = {6, 1, 5, 0, 0, 3, 8, 6, 4};
System.out.println(Arrays.toString(f(input)));
}
The last piece is not well optimized.
An other interpretation of "closest greatest:"
int[] sorted = Arrays.copyOf(values, n);
Arrays.sort(sorted);
for (int i = 0; i < n; ++i) {
int j = Arrays.binarySearch(sorted, values[i] + 1);
if (j < 0) { // Not found 1 greater.
j = ~j; // Even greater.
}
if (j < n) {
values[i] = sorted[j];
}
}
// {8, 3, 6, 4, 8, 8, 5, 0, 0}
Sorting cost O(N log N), as does the loop O(N) times binary search O(log N).
So it is faster, costing memory. But that is comparible with you stack usage.
By the way, a cleaned up version of your code could have been put on CodeReview.

Sorting list of numbers

I am trying to sort a list of numbers from smallest to the biggest and print it. I've tried two things:
1.
public class Sorter {
public static void main(String[] args) {
int[] numbers = {1, 3, 8, 2, 5, -2, 0, 7, 15};
int[] sorted = new int[numbers.length];
for (int a = 0; a < numbers.length; a++) {
int check = 0;
for (int b = 0; b < numbers.length; b++) {
if (numbers[a] < numbers[b]) {
check++;
}
}
sorted[check] = numbers[a];
}
for (int c = numbers.length - 1; c >= 0; c--) {
System.out.print(sorted[c] + ", ");
}
}
}
and this thing works, but won't work with repeated values, so I tried this other thing
public class Sortertwo {
public static void main(String[] args) {
int[] numinput = {3, 2, 1, 4, 7, 3, 17, 5, 2, 2, -2, -4};
int[] numsorted = new int[numinput.length];
int n = 0;
for (; n < numinput.length; ) {
for (int b = 0; b < numinput.length; b++) {
int check = 0;
for (int c = 0; c < numinput.length; c++) {
if (numinput[b] <= numinput[c]) {
check++;
}
}
if (check >= (numinput.length - n) && numinput[b] != 0) {
numsorted[n] = numinput[b];
numinput[b] = 0;
n++;
}
if (n >= (numinput.length)) {
break;
}
}
}
for (int g = 0; g < numinput.length; g++) {
System.out.print(numsorted[g] + ", ");
}
}
}
Where it relies on the thing that once the number from the first array is used (the smallest one is found), it has to be ignored when the program goes through the array next time around.
I tried to assign it like null value, but it doesn't work, so I assigned it to zero and then ignore it, which is a problem, because the list cant have a zero in it.
Is there any like better way to go about it? Thanks.
You can always use:
Arrays.sort(numbers);
If you want to use your first method then change this:
if (numbers[a] < numbers[b])
{
check++;
}
to:
if (numbers[a] <= numbers[b])
{
check++;
}
Unless this is homework, using Arrays.sort as the comments suggest, should be the way to go
import java.util.Arrays;
public class S {
public static void main(String ... args) {
int[] numbers = {1, 3, 8, 2, 5, -2, 0, 7, 15};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
}
}
Prints:
[-2, 0, 1, 2, 3, 5, 7, 8, 15]

Java: how to count number of non repeated elements in an integer array?

How do you count the number of numbers that occur in only one of the two arrays?
Example: countdifference([2, 4, 4, 4, 4, 6, 6, 8], [3, 4, 6, 6, 9]) returns 4 because 4 and 6 are duplicates, remaining numbers are 2, 8, 3 and 9.
noOfRepeatsCount method is intended to account for repeated elements in arrayB: i.e. 6
I am getting an index array out of bounds exception: -1 for the noOfRepeatsCount method. Any ideas why?
public class countNonRepeated {
static int countDifference(int[] arrayA, int[] arrayB) {
int count = 0, repeatCount = 0, noOfRepeatsCount = 0;
/*
int noOfRepeats = 0;
for (int k = 0; k < arrayB.length; k++) {
if (arrayB[k] == arrayB[k - 1]) {
noOfRepeats++;
} else {
continue;
}
*/
for (int i = 0; i < arrayA.length; i++) {
for (int j = 0; j < arrayB.length; j++) {
if (arrayA[i] == arrayB[j]) {
if (arrayA[i + 1] == arrayB[j]) {
repeatCount++;
} else {
count++;
}
} else {
continue;
}
}
}
int length = arrayA.length + arrayB.length;
return length - (noOfRepeatsCount * repeatCount) - (count * 2);
}
static int noOfRepeatsCount(int[] arrayB) {
int noOfRepeats = 0;
for (int k = 0; k < arrayB.length; k++) {
if (arrayB[k] == arrayB[k - 1]) {
noOfRepeats++;
} else {
continue;
}
}
return noOfRepeats;
}
public static void main(String args[]) {
int arrayA[] = { 2, 4, 4, 4, 4, 6, 6, 8 };
int arrayB[] = { 3, 4, 6, 6, 9 };
// System.out.println(noOfRepeatsCount(arrayA));
System.out.println(countDifference(arrayA, arrayB));
}
}
See the for loop in noOfRepeatsCount method. if (arrayB[k] == arrayB[k - 1]) makes exception error. Because initial k value is 0, you access arrayB[-1].
If you want to solve this problem, change for (int k = 0; k < arrayB.length; k++) to for (int k = 1; k < arrayB.length; k++).
What about converting the arrays to Sets and using a combination of removeAll(), addAll() and size() to get the desired result. I guess that this would make the algorithm clearer and avoid off-by-one errors.
I have no time right now to post a code sample, sorry.

complete a method that swaps the first and second half of an array of integers

I keep getting an out of bounds error whenever i try to run my code. Does anyone know what is wrong with it? I can't seem to figure it out.
public class Swapper{
/**
This method swaps the first and second half of the given array.
#param values an array
*/
public void swapFirstAndSecondHalf(int[] values) {
// your work here
int[] first = new int[values.length/2];
int[] second = new int[values.length/2];
for(int i = 0; i < values.length / 2; i++) {
second[i] = values[i];
}
for (int j = values.length / 2; j < values.length; j++) {
first[j] = values[j];
}
for(int k = 0; k < values.length / 2; k++) {
values[k] = first[k];
}
for(int l = values.length / 2; l < values.length; l++) {
values[l] = second[l];
}
}
// This method is used to check your work
public int[] check(int[] values) {
swapFirstAndSecondHalf(values);
return values;
}
}
int[] first = new int[values.length/2];
So indexes [0..values.length/2 - 1] are valid for first.
for (int j=values.length/2; j<values.length; j++)
{
first[j] = values[j];
}
So with the first value of j being values.length/2, it's already out of bounds.
You need to practice debugging, placing a break point and tracing the code as it executes.
You could have used System.arraycopy() instead of all the for looping.
public static void main(String[] args) throws Exception {
int[] values = {1, 2, 3, 4, 5};
values = swapFirstAndSecondHalf(values);
System.out.println(Arrays.toString(values));
values = new int[]{1, 2, 3, 4, 5, 6};
values = swapFirstAndSecondHalf(values);
System.out.println(Arrays.toString(values));
}
public static int[] swapFirstAndSecondHalf(int[] values) {
boolean evenSize = values.length % 2 == 0;
int half = values.length / 2;
int[] swapper = new int[values.length];
System.arraycopy(values, evenSize ? half : half + 1, swapper, 0, half);
System.arraycopy(values, 0, swapper, evenSize ? half : half + 1, half);
// The middle number stays the middle number
if (!evenSize) {
swapper[half] = values[half];
}
return swapper;
}
Results:
[4, 5, 3, 1, 2]
[4, 5, 6, 1, 2, 3]
If you're wanting the middle number, for an odd sized array, to be part of the second half then the swapFirstAndSecondHalf() would look like this:
public static int[] swapFirstAndSecondHalf(int[] values) {
boolean evenSize = values.length % 2 == 0;
int half = values.length / 2;
int[] swapper = new int[values.length];
System.arraycopy(values, half, swapper, 0, evenSize ? half : half + 1);
System.arraycopy(values, 0, swapper, evenSize ? half : half + 1, half);
return swapper;
}
Results:
[4, 5, 3, 1, 2]
[4, 5, 6, 1, 2, 3]
Allocating new arrays is a waste of space. Just swap the halves in-place:
public static void swapFirstAndSecondHalf(int[] values) {
final int len = values.length / 2;
final int offset = values.length - len;
for (int i = 0; i < len; i++) {
int temp = values[i];
values[i] = values[offset + i];
values[offset + i] = temp;
}
}
The code allows odd length, and will leave center value alone.

Breadth First Traversal using adj Matrix

I'm writing breadth first, depth first, and depth first recursive traversal for the following graph:
From what I understand, the traversal should be 0 1 3 6 4 5 2...but i'm only getting that for the depth first traversal, and for the dfs(recursive) and BFS, I'm getting 0 1 3 6 2 4 5. I don't know which one is right and what I need to do to fix the problem.
Class
public void depthFirst(int vFirst,int n, int[] isvisited)
{ //vFirst = 0, n = 6
int v,i;
// st is a stack
st.push(vFirst);
while(!st.isEmpty())
{
v = st.pop();
if(isvisited[v]==0)
{
System.out.print(v);
isvisited[v]=1;
}
for ( i = 0; i <= n; i++)
{
if((adjMatrix[v][i] == 1) && (isvisited[i] == 0))
{
st.push(v);
isvisited[i]=1;
System.out.print(" " + i);
v = i;
}
}
}
}
public void depthFirstRecursive(int w) {
int j; //w = 0;
visited[w] = 1;
if (w == 0) {
System.out.print(w + " ");
}
for (j = 0; j <= 6; j++) {
if ((adjMatrix[w][j] == 1) && (visited[j] == 0)) {
System.out.print(j + " ");
depthFirstRecursive(j);
}
}
}
public void breadthFirst(int first, int p) {
int e; // first = 0; p = 6
int[] nodeVisited = new int[7];
que.add(first);
while (!que.isEmpty()) {
e = que.remove();
if(nodeVisited[e]==0)
{
System.out.print(e);
nodeVisited[e]=1;
}
for (int i = 0; i <= p; i++)
{
if((adjMatrix[e][i] == 1) && (nodeVisited[i] == 0))
{
que.add(e);
nodeVisited[i]=1;
System.out.print(" " + i);
e = i;
}
}
}
}
public static void main(String[] args) {
// 1 2 3 4 5 6 7
int[][] adjMatrix = { {0, 1, 1, 0, 0, 0, 0},
{1, 0, 0, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0 ,0},
{0, 0, 1, 1, 1, 0, 0} };
new myGraphs(adjMatrix);
}
About following snippet in BFS:
que.add(e);
nodeVisited[i]=1;
System.out.print(" " + i);
e = i;
They why do you change e and add e to queue? It seems incorrect to me.
Non Recursive BFS using Queue:
public int[] breadthFirstSearch(int[][] adjacencyMatrix, int start) {
int totalNumberOfvertices = adjacencyMatrix.length;
boolean[] visited = new boolean[totalNumberOfvertices];
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
visited[start] = true;
List<Integer> list = new ArrayList<>();
while (!queue.isEmpty()) {
list.add(queue.peek());
int currentFirstElementInQueue = queue.poll();
for (int i = 0; i < adjacencyMatrix.length; i++) {
if ((adjacencyMatrix[currentFirstElementInQueue][i] == 1) && (!visited[i])) {
queue.add(i);
visited[i] = true;
}
}
}
int[] result = new int[list.size()];
int i = 0;
Iterator<Integer> itr = list.iterator();
while (itr.hasNext()) {
result[i++] = itr.next();
}
return result;
}
public void BFS(int start)
{
int v=a.length;//a[][] is adj matrix declared globally
boolean visited[]=new boolean[v];//indexing done from 1 to n
LinkedList<Integer> queue=new LinkedList<Integer>();
visited[start]=true;
queue.add(start);
while(queue.size()!=0)
{
int x=queue.remove();
System.out.print(x+" ");
for (int i=1; i < v; i++)
if((a[x][i] == 1) && (!visited[i]))
{
queue.add(i);
visited[i]=true;
}
}
}

Categories