题目地址:
https://leetcode.com/problems/the-maze/
给定一个二维 0 − 1 0-1 0−1矩阵, 0 0 0代表空地, 1 1 1代表障碍物。在某个空地上有个小球,它可以沿着四个方向滑动,每次滑动时只有遇到边界或者障碍物才会停下来。再给定一个空地作为终点,问该小球是否可能滑到终点。
思路是BFS。一步一步向外扩展,直到走到终点或者扩展不下去了为止。代码如下:
import java.util.*;
public class Solution {
public boolean hasPath(int[][] maze, int[] start, int[] destination) {
if (maze == null || maze.length == 0 || maze[0].length == 0) {
return false;
}
// 四个方向
int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
Queue<int[]> queue = new LinkedList<>();
// 判断某个位置是否访问过
boolean[][] visited = new boolean[maze.length][maze[0].length];
queue.offer(new int[]{start[0], start[1]});
visited[start[0]][start[1]] = true;
while (!queue.isEmpty()) {
int[] cur = queue.poll();
for (int[] next : getNexts(cur[0], cur[1], maze, dirs, visited)) {
// 如果next等于终点,说明终点可以到达了,返回true
if (Arrays.equals(next, destination)) {
return true;
}
queue.offer(next);
visited[next[0]][next[1]] = true;
}
}
// 队列为空意味着无法扩展下去,返回false
return false;
}
// 返回从maze[x][y]沿着四个方向滑动会停下来的地方
private List<int[]> getNexts(int x, int y, int[][] maze, int[][] dirs, boolean[][] visited) {
List<int[]> nexts = new ArrayList<>();
for (int i = 0; i < dirs.length; i++) {
int dx = dirs[i][0], dy = dirs[i][1];
int step = 1;
while (inBound(x + step * dx, y + step * dy, maze) && maze[x + step * dx][y + step * dy] == 0) {
step++;
}
// 回退一格才是真正停下来的地方
step--;
int nextX = x + step * dx, nextY = y + step * dy;
if (!visited[nextX][nextY]) {
nexts.add(new int[]{nextX, nextY});
}
}
return nexts;
}
private boolean inBound(int x, int y, int[][] maze) {
return 0 <= x && x < maze.length && 0 <= y && y < maze[0].length;
}
}
时空复杂度 O ( m n ) O(mn) O(mn)。