Input: maze = [[“+”,“+”,“.”,“+”],[“.”,“.”,“.”,“+”],[“+”,“+”,“+”,“.”]], entrance = [1,2]
Output: 1
Explanation: There are 3 exits in this maze at [1,0], [0,2], and [2,3].
Initially, you are at the entrance cell [1,2].
- You can reach [1,0] by moving 2 steps left.
- You can reach [0,2] by moving 1 step up.
It is impossible to reach [2,3] from the entrance.
Thus, the nearest exit is [0,2], which is 1 step away.
给一个迷宫,“.“代表此路可走,”+“代表此路不通,
给一个entrance的位置作为初始位置。
从初始位置出发,走到迷宫的边界处,如果边界处是“.”, 就说明到达了出口,返回最短的路径。
初始位置即使在边界处,也不能算作出口。
如果不存在能走出去的路径,返回-1.
思路:
第一时间想到的竟然是DFS而不是BFS。
下面来说明DFS是如何TLE的。虽然走不通,但是还是过一下。
DFS流程是下面这样的,
注意当前节点访问完,visited要变回false, 不然当前路径即使尝试失败,后面其他路径再想经过也会被堵。
int dfs(char[][] maze, int r, int c, boolean[][] visited, int steps) {
if(r < 0 || c < 0 || r > m || c > n) return 1000;
if(visited[r][c] || steps >= 1000) return 1000;
if(maze[r][c] == '+') return 1000;
if((r == 0 || r == m || c == 0 || c == n) && maze[r][c] == '.') {
steps ++;
return steps;
}
visited[r][c] = true;
steps ++;
int step1 = dfs(maze, r-1, c, visited, steps);
int step2 = dfs(maze, r, c+1, visited, steps);
int step3 = dfs(maze, r+1, c, visited, steps);
int step4 = dfs(maze, r, c-1, visited, steps);
visited[r][c] = false;
return Math.min(Math.min(step1, step2), Math.min(step3, step4));
}
来看看DFS为神马会TLE。
从(17, 15)的"E"处出发,
如果是DFS,先探索从(16, 15)出发的路径的话,那可有得探索了,上面各种尝试,然而绕一大圈回来发现出口就在家门口。
那你说我改个方向,先探索从(17, 16)出发的路径,那么这个case是没问题了,entrance如果在第0列不还是会有这个问题么。
这种找最短路径,要突出一个短,按半径从小到大一圈一圈搜索,更容易快速找到出口。
BFS中有个问题是什么时候设置visited flag? 是访问到当前节点的时候,还是把下一节点装入queue的时候?
帮你们做了个实验,访问当前节点的时候steps++ 会 TLE,
为什么,因为装入queue就说明下一轮即将被访问,此时不设visited, 那该节点可能会被重复装入queue。
也可以不用visited二维数组,直接把访问过的地方设为“ + “ 也是一样的效果,不过就会改变原maze数组了。
public int nearestExit(char[][] maze, int[] entrance) {
int m = maze.length;
int n = maze[0].length;
Queue<int[]> queue = new LinkedList<>();
int steps = 0;
int[] direc = new int[]{-1, 0, 1, 0, -1};
boolean[][] visited = new boolean[m][n];
visited[entrance[0]][entrance[1]] = true;
queue.offer(entrance);
while(!queue.isEmpty()) {
steps ++;
int size = queue.size();
for(int s = 0; s < size; s++) {
int[] cur = queue.poll();
//visited[cur[0]][cur[1]] = true; //不要在这里设为true
for(int i = 0; i < 4; i++) {
int nextR = cur[0] + direc[i];
int nextC = cur[1] + direc[i+1];
if(nextR < 0 || nextR >= m || nextC < 0 || nextC >= n) continue;
if(visited[nextR][nextC]) continue;
if(maze[nextR][nextC] == '+') continue;
if(nextR == 0 || nextR == m-1 || nextC == 0 || nextC == n-1) return steps;
visited[nextR][nextC] = true; //装入queue时设为true,防止节点被重复装入queue
queue.offer(new int[]{nextR, nextC});
}
}
}
return -1;
}