Here 's the LeetCode problem 542. 01 Matrix
My code will create an infinite loop because it will push every directions into the queue, even if that node has already been visited.
I can't think of a way to solve this problem. Could anyone help?
class Solution {
int[][] dirs = { {0,1},{0,-1},{1,0},{-1,0} };
public int[][] updateMatrix(int[][] matrix) {
for(int i=0;i < matrix.length;i++){
for(int j=0; j < matrix[i].length;j++){
if(matrix[i][j] == 1)
matrix[i][j] = Integer.MAX_VALUE;
BFS(new int[]{i,j},matrix);
}
}
return matrix;
}
public void BFS(int[] node,int[][] matrix){
if(matrix[node[0]][node[1]] == 0)
return;
LinkedList<int[]> queue = new LinkedList<>();
queue.push(node);
int step = 1;
while(!queue.isEmpty()){
int[] temp = queue.poll();
if(temp == null){
step++;
continue;
}
for(int[] dir:dirs){
int r = temp[0] + dir[0];
int c = temp[1] + dir[1];
if(r < 0 || c < 0 || r >= matrix.length || c >= matrix[r].length)
continue;
queue.push(new int[] {r,c});
if(matrix[r][c] == 0){
matrix[temp[0]][temp[1]] = Math.min(step,matrix[temp[0]][temp[1]]);
}
}
queue.push(null);
}
return;
}
}
You must keep track of the nodes that were already visited. You can either keep the nodes in the list, or move them to a separate Set.
The problem you have here is that the nodes are arrays, and you cannot use them in a HashSet. I would start by declaring a class Coordinates:
public class Coordinates {
public final int row;
public final int col;
public Coordinates(int r, int c) {
this.row = r;
this.col = c;
}
#Override
public int hashCode() {
return (row + 37*col) & 0x7FFFFFFF;
}
#Override
public boolean equals(Object other) {
if (other == null || other.getClass() != getClass()) {
return false;
}
Coordinates o = (Coordinates)other;
return row == o.row && col == o.col;
}
}
Option 1: keeping the nodes in the queue
I didn't understand the purpose of adding nulls into the queue; I just removed this.
public void BFS(Coordinates node,int[][] matrix){
if(matrix[node.row][node.col] == 0)
return;
List<Coordinates> queue = new ArrayList<>();
queue.add(node);
for (int i = 0; i < queue.size(); ++i) {
Coordinates temp = queue.get(i);
for(int[] dir:dirs){
int r = temp.row + dir.row;
int c = temp.col + dir.col;
if(r < 0 || c < 0 || r >= matrix.length || c >= matrix[r].length)
continue;
Coordinates newCoord = new Coordinates(r, c);
if (!queue.contains(newCoord)) {
queue.add(newCoord);
}
if(matrix[r][c] == 0){
matrix[temp.row][temp.col] = Math.min(step,matrix[temp.row][temp.col]);
}
}
}
return;
}
Option 2: use a separate Set
Now that we have a hashCodeand an equals method, why not use a HashSet?
I will leave this as an exercise though.
Encapsulate the node address in a class that can implement hashcode and equals, as proposed in this answer. Node class can be as simple as :
class Node {
private final int[] address;
Node(int[] address){
this.address = address;
}
#Override
public boolean equals(Object other) {
if(other == null ||!(other instanceof Node)) return false;
return Arrays.equals(address, ((Node)other).getAddress());
}
#Override
public int hashCode() {
return Arrays.hashCode(address);
}
public int[] getAddress() {
return address;
}
}
It allows you to maintain a collection of visited nodes : Set<Node> visited = new HashSet<>();
When visited.add(node) returns false, you know that visited already contains node
The problem is a binary maze where 1's are walls and 0's are valid paths. You start from the top left (0,0) and you have to reach the bottom right (width -1, height -1). You have to find the shortest path from the top left to the bottom right. The twist comes in because you are allowed to remove one wall at most and this is the part that is confusing me. My current code can solve the shortest path without calculating for a wall being removed.
Here are a couple of examples:
[0,1,1,0], [0,0,0,1], [1,1,0,0], [1,1,1,0] Answer: 7 moves (including entrance and exit)
Example 2:
[0,0,0,0,0],[0,1,1,1,0],[1,0,0,0,0],[0,1,1,1,1],[0,1,1,1,1],[0,0,0,0,0] Answer: 11 (Because you can break the wall at position [0][1] to make the path shorter)
So like I said before my code will find the shortest path, but at the moment doesn't try to remove a wall for a shorter path, mostly because I dont understand how to. I was thinking that I remove one wall at a time and continually re-run to see if a shorter path is produced but this seems very costly operation, but it might get the job done. However, I was hoping that I could find a more clear and easier way to do so.
import java.util.*;
public class Maze {
public static void main(String [] args)
{
int[][] arr = new int[][] {
{0,0,0,0,0},
{1,1,1,1,0},
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,1,1,1},
{0,0,0,0,0},
};
answer(arr);
}
public static int answer(int[][] maze) {
maze[maze.length-1][maze[0].length -1] = 9;
Point p = getPathBFS(0,0,maze);
int length = 1;
while(p.getParent() != null) {
p = p.getParent();
length++;
}
System.out.println(length);
return length;
}
private static class Point {
int x;
int y;
Point parent;
public Point(int x, int y, Point parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent() {
return this.parent;
}
}
public static Queue<Point> q = new LinkedList<Point>();
public static Point getPathBFS(int x, int y,int[][] arr) {
q.add(new Point(x,y, null));
while(!q.isEmpty()) {
Point p = q.remove();
if (arr[p.x][p.y] == 9) {
return p;
}
if(isFree(p.x+1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x+1,p.y, p);
q.add(nextP);
}
if(isFree(p.x-1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x-1,p.y, p);
q.add(nextP);
}
if(isFree(p.x,p.y+1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y+1, p);
q.add(nextP);
}
if(isFree(p.x,p.y-1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y-1, p);
q.add(nextP);
}
}
return null;
}
public static boolean isFree(int x, int y,int[][] arr) {
if((x >= 0 && x < arr.length) && (y >= 0 && y < arr[x].length) && (arr[x][y] == 0 || arr[x][y] == 9)) {
return true;
}
return false;
}
}
The thing to notice is the fact that shortest path through the maze with removing a section consists of two shortest paths - from entrance to removed section and then from removed section to exit.
You can use BFS to calculate distances of all positions in the maze from the starting location and distances of all positions from ending location.
Then you can find a position for which the sum of distances to entrance and to exit is minimal. If it is a wall section then it is the section to remove. Otherwise, removing any section is not useful.
Overall, this solution runs in linear time.
You use a Point class to represent the position of the player as he walks through the maze. Without the wall rule, this position is all you need to know about the player to determine what he can do next, and so you can do BFS on the directed graph of all possible positions to find the path.
With the wall rule, in order to determine where the player can go next, you also have to know whether or not he has already removed a wall, so the full state of the player includes not only his position, but also a boolean that indicates whether or not a wall has been removed.
You can then do BFS on the graph of these expanded states to find the shortest path with at most one wall removed.
Since you've posted your actual code for the simpler problem, I'll just fix it up with the expanded state (and a Set to keep you from visiting the same state twice, instead of modifying arr):
import java.util.*;
public class Maze {
public static void main(String [] args)
{
int[][] arr = new int[][] {
{0,0,0,0,0},
{1,1,1,1,0},
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,1,1,1},
{0,0,0,0,0},
};
answer(arr);
}
public static int answer(int[][] maze) {
maze[maze.length-1][maze[0].length -1] = 9;
State p = getPathBFS(0,0,maze);
int length = 1;
while(p.getParent() != null) {
p = p.getParent();
length++;
}
System.out.println(length);
return length;
}
private static class State {
int x;
int y;
boolean wallRemoved;
State parent;
public State(int x, int y, boolean wallRemoved, State parent) {
this.x = x;
this.y = y;
this.wallRemoved = wallRemoved;
this.parent = parent;
}
public State getParent() {
return this.parent;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (wallRemoved ? 1231 : 1237);
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null ||getClass() != obj.getClass())
return false;
State other = (State) obj;
if (wallRemoved != other.wallRemoved)
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
public static Queue<State> q = new LinkedList<>();
public static HashSet<State> seen = new HashSet<>();
public static State getPathBFS(int x, int y,int[][] arr) {
q.add(new State(x,y,false, null));
while(!q.isEmpty()) {
State p = q.remove();
if (arr[p.x][p.y] == 9) {
return p;
}
tryNext(p,p.x+1,p.y,arr);
tryNext(p,p.x-1,p.y,arr);
tryNext(p,p.x,p.y+1,arr);
tryNext(p,p.x,p.y-1,arr);
}
return null;
}
public static void tryNext(State p, int x, int y, int[][]arr) {
if (x<0 || y<0 || x>=arr.length || y>=arr[x].length)
return;
State newState;
if (arr[x][y] == 0 || arr[x][y]==9) {
newState = new State(x, y, p.wallRemoved, p);
} else if (!p.wallRemoved) {
newState = new State(x, y, true, p);
} else {
return;
}
if (seen.add(newState)) {
q.add(newState);
}
}
}
import java.util.TreeMap;
class Point implements Comparable<Point>{
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object arg0) {
Point p = (Point) arg0;
return (this.x == p.x && this.y == p.y);
}
#Override
public String toString() {
return "("+x+", "+y+")";
}
#Override
public int compareTo(Point arg0) {
if(this.x == arg0.x && this.y == arg0.y)
return 0;
return -1;
}
}
public class Test {
static int row, col;
static TreeMap<Point, Integer> dist;
public static void main(String[] args) {
dist = new TreeMap<>();
row = 4;
col = 7;
for(int i=0; i<row; i++){
for(int j=0; j<col; j++){
Point p = new Point(i, j);
dist.put(p, Integer.MAX_VALUE);
}
if(i >= 1)
System.out.println(i+": "+dist.keySet().contains(new Point(1, 5)));
}
}
}
The output should be:
1: true
2: true
3: true
but its coming
1: true
2: false
3: false
can some one please explain why is this output coming?
this code is working fine if i am taking predefined data types
as key to the map.
can some one please explain why is this output coming?
this code is working fine if i am taking predefined data types
as key to the map.
Your compareTo is not transitive anti-symmetric. See here for more detail.
#Override
public int compareTo(Point arg0) {
if(this.x == arg0.x && this.y == arg0.y)
return 0;
return -1;
}
When a!=b, a.compareTo(b) returns -1, but b.compareTo(a) also returns -1. This leads to incorrect sorting.
As #RobAu points out, the problem is your compareTo method. Note the documentation of that method:
Returns a negative integer, zero, or a positive integer as this object
is less than, equal to, or greater than the specified object.
You need to modify your code to allow for proper comparison between points, that is, you have to come up with some ordering for points. For instance, here is an alternative implementation that works:
#Override
public int compareTo(Point arg0) {
int ret = Integer.compare(x, arg0.x);
if (ret == 0) {
ret = Integer.compare(y, arg0.y);
}
return ret;
}
I would like to ask how do we find the element in an array with the value of a variable inside the element? Is it possible? If so, please do tell. Suppose we have an object called Pt:
public class Pt {
private int x, y;
public void setCoords(int i, int j){
x = i;
y = j;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
Then we create an Array of Pt object and also initialize it's elements.
Pt[] point;
point[0].setCoords(0,0);
point[1].setCoords(1,1);
The problem that I am having now is how do I find the element with the coordinates (1,1)?
You just need to loop through the array and check each of the elements. To loop through the array, you can use an enhanced for loop.
for (Pt pt : point) {
if(pt.getX() == 1 && pt.getY() == 1){
//what you want to do with the object...
break;
}
}
public static void main(String[] args) {
Pt[] point = new Pt[2];
Pt pt1 = new Pt();
pt1.setCoords(0, 0);
Pt pt2 = new Pt();
pt2.setCoords(1, 1);
point[0] = pt1;
point[1] = pt2;
getElement(point, 1, 1); // returns element with coords of (1, 1) or null if doesn't exist
}
public static Pt getElement(Pt[] point, int xCoord, int yCoord) {
for (int i = 0; i < point.length; i++) {
if (point[i].getX() == xCoord && point[i].getY() == yCoord) {
return point[i];
}
}
return null;
}
I have this class to hold two values:
public class Coord {
public int x;
public int y;
public Coord(int x, int y) {
this.x = x;
this.y = y;
}
}
I am trying to use it in a depth-first search algorithm:
x = this.move_to_x;
y = this.move_to_y;
Coord stack = new Coord(0, 0);
Stack<Coord> start = new Stack<Coord>();
Stack<Coord> visited = new Stack<Coord>();
start.push(stack);
visited.push(stack);
while (!start.empty()) {
Coord tmp = (Coord)start.pop();
int j,k;
j = tmp.x;
k = tmp.y;
// there is only 8 possible ways to go (the neighbors)
for (int a = -1; a < 2; a++) {
tmp.x = j + a;
for (int b = -1; b < 2; b++) {
if (a == 0 && b == 0) {
continue;
}
tmp.y = k + b;
if (tmp.x < 0 || tmp.y < 0) {
continue;
}
if (tmp.x > 5 || tmp.y > 5) {
continue;
}
if (tmp.x == x && tmp.y == y) {
System.out.println("end!");
return;
}
Coord push = new Coord(tmp.x, tmp.y);
System.out.println("visited: " + visited);
if (visited.search(push) == -1) {
System.out.println("added x " + push.x + " y " + push.y
+ " " + visited.search(push));
start.push(push);
visited.push(push);
} else {
System.out.println("visited x " + tmp.x + " y " + tmp.y
+ " index " + visited.search(push));
}
}
}
}
The problem is that the visited.search method is always returning -1. Here is the log:
visited: [Agent.ExampleAgent.Coord#1af6a711]
added x 0 y 1 -1
visited: [Agent.ExampleAgent.Coord#1af6a711, Agent.ExampleAgent.Coord#1c727896]
added x 1 y 0 -1
visited: [Agent.ExampleAgent.Coord#1af6a711, Agent.ExampleAgent.Coord#1c727896, Agent.ExampleAgent.Coord#5fbd8c6e]
added x 1 y 1 -1
visited: [Agent.ExampleAgent.Coord#1af6a711, Agent.ExampleAgent.Coord#1c727896, Agent.ExampleAgent.Coord#5fbd8c6e, Agent.ExampleAgent.Coord#427a8ba4]
added x 0 y 0 -1
visited: [Agent.ExampleAgent.Coord#1af6a711, Agent.ExampleAgent.Coord#1c727896, Agent.ExampleAgent.Coord#5fbd8c6e, Agent.ExampleAgent.Coord#427a8ba4, Agent.ExampleAgent.Coord#262f6be5]
added x 0 y 1 -1
visited: [Agent.ExampleAgent.Coord#1af6a711, Agent.ExampleAgent.Coord#1c727896, Agent.ExampleAgent.Coord#5fbd8c6e, Agent.ExampleAgent.Coord#427a8ba4, Agent.ExampleAgent.Coord#262f6be5, Agent.ExampleAgent.Coord#199d4a86]
Note that the first element that is added to the visited stack is (0,1), however when it is searched for (0,1), later the method returns -1.
(Figured I'd post an answer outlining the progress we made in our chat discussion)
Assuming the following state of the Coord class:
public class Coord {
public int x;
public int y;
public Coord(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj){
if (obj == null)
return false;
if (obj.getClass() != Coord.class)
return false;
if (obj == this)
return true;
Coord a = (Coord)obj;
return (a.x == this.x && a.y == this.y);
}
#Override
public int hashCode() {
return x*17 + y*31;
}
#Override
public String toString() {
return "("+x+", "+y+")";
}
}
... that implements:
equals() as this is what stack search uses, according to its Javadoc
hashCode() as a best practice, accompanying equals()
toString() for clearer diagnostic output
The idea is to test the functionality of stack search in isolation from the rest of the code. If we can prove that stack search functions properly, then the problem is in elsewhere.
Proving that the stack search works can be done using a test class, such as this one:
public class CoordTest {
public static void main(String[] args) {
System.out.println("Running tests...");
System.out.println("Testing: equals");
Coord c1a = new Coord(2,3);
Coord c1b = new Coord(2,3);
check(c1a.equals(c1b));
System.out.println("Testing: not equals");
Coord c2a = new Coord(2,3);
Coord c2b = new Coord(6,8);
Coord c2c = new Coord(2,8);
Coord c2d = new Coord(6,3);
check(!c2a.equals(c2b));
check(!c2a.equals(c2c));
check(!c2a.equals(c2d));
System.out.println("Testing: not found in empty stack");
Stack<Coord> stack1 = new Stack<Coord>();
int result1 = stack1.search(c1a);
check(result1 == -1);
System.out.println("Testing: not found in non-empty stack");
Stack<Coord> stack2 = new Stack<Coord>();
stack2.push(new Coord(4,5));
stack2.push(new Coord(6,7));
int result2 = stack2.search(c1a);
check(result2 == -1);
System.out.println("Testing: found in non-empty stack");
Stack<Coord> stack3 = new Stack<Coord>();
stack3.push(new Coord(4,5));
stack3.push(new Coord(3,1));
stack3.push(new Coord(6,7));
int result3 = stack3.search(new Coord(3,1));
check(result3 == 2);
System.out.println("All tests completed successfully.");
}
private static void check(boolean condition) {
if (!condition) {
throw new RuntimeException("Condition failed!");
}
}
}
Output:
Running tests...
Testing: equals
Testing: not equals
Testing: not found in empty stack
Testing: not found in non-empty stack
Testing: found in non-empty stack
All tests completed successfully.
You need to override the equals() method so it returns true if x and y of the parameter are equal to the object's x and y values.
You should also override the hashCode() method so that it "agrees" with the equals() method.