[英]Java: Efficient way to print shortest path in 2d Matrix
下面是找出最短路徑的代碼,我試圖只打印最短路徑,但我得到了所有可能訪問過的路徑,我能夠在 Python 中做到這一點,但我很難在 Java 中做到這一點,我想知道在 Java 中是否有更好的方法來做到這一點。
Python 解決方案
def helper(grid):
m,n=len(grid),len(grid[0])
deque=collections.deque([[(0,0)]])
seen=set()
while deque:
arr=deque.popleft()
i,j=arr[-1]
if (i,j)==(m-1,n-1):
return arr
seen.add((i,j))
possible=[(x,y) for x,y in [(i+1,j),(i-1,j),(i,j+1),(i,j-1)] if 0<=x<m and 0<=y<n and grid[x][y]!=1]
for x,y in possible:
if (x,y) not in seen:
deque.append(arr+[(x,y)])
grid=[
[0,0,0,0,0,0,0],
[0,0,1,0,0,1,0],
[0,0,1,0,1,1,0],
[0,0,1,0,1,0,1],
[1,1,1,0,0,0,0]
]
print(helper(grid))
Python 代碼將預期的 output 打印為(0, 0) -> (0, 1) -> (0, 2) -> (0, 3) -> (1, 3) -> (2, 3) -> (3, 3) -> (4, 3) -> (4, 4) -> (4, 5) -> (4, 6)
Java
import java.util.*;
class Main {
private static int[][] dir = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
public static void main(String[] args) {
int[][] grid = {
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 1, 0},
{0, 0, 1, 0, 1, 1, 0},
{0, 0, 1, 0, 1, 0, 1},
{1, 1, 1, 0, 0, 0, 0}
};
int[][] path = shortestPath(grid);
System.out.println("shortestPath " + Arrays.deepToString(path));
}
public static int[][] shortestPath(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
if (grid == null || grid.length == 0 || grid[0][0] == 1 || grid[m - 1][n - 1] == 1) return new int[][]{{-1, -1}};
int[][] path = bfs_with_visited(grid, m, n);
return path;
}
private static int[][] bfs_with_visited(int[][] grid, int m, int n) {
boolean[][] visited = new boolean[m][n];
visited[0][0] = true;
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{0, 0});
List<int[]> result = new ArrayList<>();
int path = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] currentCell = queue.remove();
result.add(new int[]{currentCell[0], currentCell[1]});
if (currentCell[0] == m - 1 && currentCell[1] == n - 1) {
return result.toArray(new int[result.size()][2]);
}
visitNeighbours(grid, m, n, visited, queue, currentCell);
}
path++;
}
return new int[][]{{-1, -1}};
}
private static void visitNeighbours(int[][] grid, int m, int n, boolean[][] visited, Queue<int[]> queue, int[] currentCell) {
for (int k = 0; k < dir.length; k++) {
int nextX = dir[k][0] + currentCell[0];
int nextY = dir[k][1] + currentCell[1];
if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n && !visited[nextX][nextY] && grid[nextX][nextY] == 0) {
queue.add(new int[]{nextX, nextY});
visited[nextX][nextY] = true;
}
}
}
}
感謝您的投入,TIA。
在您的 python 程序中,如果您在arr = deque.popleft()
之后放置打印語句,您將看到以下內容:
[(0, 0)]
[(0, 0), (1, 0)]
[(0, 0), (0, 1)]
[(0, 0), (1, 0), (2, 0)]
[(0, 0), (1, 0), (1, 1)]
[(0, 0), (0, 1), (1, 1)]
[(0, 0), (0, 1), (0, 2)]
[(0, 0), (1, 0), (2, 0), (3, 0)]
[(0, 0), (1, 0), (2, 0), (2, 1)]
[(0, 0), (1, 0), (1, 1), (2, 1)]
[(0, 0), (0, 1), (1, 1), (2, 1)]
[(0, 0), (0, 1), (0, 2), (0, 3)]
[(0, 0), (1, 0), (2, 0), (3, 0), (3, 1)]
[(0, 0), (1, 0), (2, 0), (2, 1), (3, 1)]
[(0, 0), (1, 0), (1, 1), (2, 1), (3, 1)]
[(0, 0), (0, 1), (1, 1), (2, 1), (3, 1)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (1, 4)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 4)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 6)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (4, 4)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 6), (2, 6)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (4, 4), (4, 5)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (4, 4), (4, 5), (3, 5)]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (4, 4), (4, 5), (4, 6)]
如果你能看到,python 程序將一個列表附加到隊列中,而不僅僅是一個坐標,這意味着它會記住它經過的路徑,或者換句話說,它一直攜帶着路徑。
如果你想在 Java 中模擬同樣的東西,你可以這樣做:
private static int[][] bfs_with_visited(int[][] grid, int m, int n) {
boolean[][] visited = new boolean[m][n];
visited[0][0] = true;
Deque<List<int[]>> queue = new ArrayDeque<>();
List<int[]> result = new ArrayList<>();
result.add(new int[] {0,0});
queue.addFirst(result);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i <size; i++ ) {
result = queue.removeFirst();
int[] curr = result.get(result.size()-1);
if (curr[0] == m-1 && curr[1] == n-1) {
return result.toArray(new int[result.size()][2]);
}
visited[curr[0]][curr[1]] = true;
visitNeighbours(grid, m, n, visited, queue, result, curr);
}
}
return new int[][]{{-1, -1}};
}
private static void visitNeighbours(int[][] grid, int m, int n, boolean[][] visited, Deque<List<int[]>> queue,
List<int[]> listSoFar, int[] currentCell) {
for (int k = 0; k < dir.length; k++) {
int nextX = dir[k][0] + currentCell[0];
int nextY = dir[k][1] + currentCell[1];
if (nextX >= 0 && nextX < m && nextY >= 0 && nextY < n && !visited[nextX][nextY] && grid[nextX][nextY] == 0) {
List<int[]> l = new ArrayList<>(listSoFar);
l.add(new int[] {nextX, nextY});
queue.add(l);
}
}
}
但我不會建議這個。 而是創建一個 class 之類的
class Node {
int[] prev = null;
int[] curr = null;
public Node(int[] curr, int[] prev) {
this.curr = curr;
this.prev = prev;
}
}
並使用它來填充您的隊列。 當您找到目標Node
時,使用prev
字段跟蹤路徑,直到到達 null prev
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.