题目地址:
https://www.lintcode.com/problem/the-maze/description
给定一个二维数组,其表示一个迷宫, 0 0 0代表空地, 1 1 1代表障碍物,不含其它数字。再给定一个出发点和一个终点,题目保证出发点和终点都是空地。现在有一个小球从出发点出发,其可沿着四个方向直线滑行,直到遇到边界或者障碍物才能停下来。问是否存在一种滑行的可能,使得小球停在终点。
可以用BFS来解决。用一个队列记录小球每次滑行所滑到的目标点,然后再用一个哈希表来记录某个点是否之前滑到过。这里可以采取将二维坐标序列化为字符串的方式加入哈希表。每次滑行的时候都看一下是否到达了终点,如果到了直接返回true,否则继续尝试四个方向的滑行,直到所有可能的点都访问完毕为止。代码如下:
import java.util.*;
public class Solution {
/**
* @param maze: the maze
* @param start: the start
* @param destination: the destination
* @return: whether the ball could stop at the destination
*/
public boolean hasPath(int[][] maze, int[] start, int[] destination) {
// write your code here
Queue<int[]> queue = new LinkedList<>();
Set<String> visited = new HashSet<>();
// 先将出发点加入队列和哈希表
queue.offer(start);
visited.add(start[0] + "," + start[1]);
while (!queue.isEmpty()) {
int[] cur = queue.poll();
// 将下一次可以滑到并且之前未访问过的点取出来
List<int[]> dest = getDestination(cur, maze, visited);
for (int[] pos : dest) {
// 如果到达了终点,直接返回true
if (Arrays.equals(pos, destination)) {
return true;
}
// 否则将这个点加入队列和哈希表,下一次从这个点开始滑行
String posString = pos[0] + "," + pos[1];
queue.offer(pos);
visited.add(posString);
}
}
return false;
}
private List<int[]> getDestination(int[] cur, int[][] maze, Set<String> visited) {
int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
List<int[]> dest = new ArrayList<>();
for (int i = 0; i < 4; i++) {
int x = cur[0], y = cur[1];
while (inBoard(x, y, maze) && maze[x][y] != 1) {
x += dirs[i][0];
y += dirs[i][1];
}
x -= dirs[i][0];
y -= dirs[i][1];
if (!visited.contains(x + "," + y)) {
dest.add(new int[]{x, y});
}
}
return dest;
}
private boolean inBoard(int x, int y, int[][] maze) {
return 0 <= x && x < maze.length && 0 <= y && y < maze[0].length;
}
}
时空复杂度 O ( n ) O(n) O(n), n n n为迷宫的规模。