https://leetcode.com/problems/robot-room-cleaner/
这一题,我第一次面fb的时候,被挂过。所以还是想过一下的。这题只能dfs做,因为它的限制就是你只能一格格一步步走,没办法像bfs所需要的那样跳着格子一层层的走。所以你要做的就是每到一个格子,就四个方向走,同时用某种方式记录你走过的位置以免重复走,但是你这玩意儿,它还需要回头走回你来的方向的,所以你还需要一种方式走你走过的路以回到原点。其实这也不是很难,在当前的dfs层级,你需要记录你来时的方向,然后允许你回头走即可。做法应该不是唯一的,而我的做法是这样的。
1. 在当前层级clean,记录自己visited过这个坐标,左转一次。
2. 然后开始顺时针右转四次,在右转前尝试是否能前进,如果可以,就前进到下一格,并在返回的时候左转(因为返回的时候你的方向已经转了180度了,所以此时左转就相当于右转),如果不能前进或者将要前进的方向已经visited过了,就直接右转。这个操作就相当于尝试在四个方向进行dfs。(其实本来只需要三次即可,因为除却初始点,最后一个方向永远是你来时的方向,但是正因为有初始点,所以四个方向都必须要尝试)。
3. 当四次右转以及对应的dfs完成之后,左转一次,你就面向你了来时的方向,然后通过move回去到上一个dfs层级即可。譬如说你在这个点最开始朝左,然后你左转了一次变成朝下,当你dfs了四次并且右转了四次转了360度之后又变成了朝下,此时左转一次,你就变成了朝右,就可以回到你上一个点。
这里还有两个要注意的地方, 这题是没有一个坐标数据譬如说二维数组之类的给你的,所以你得假设有一个x,y坐标系,然后起点永远是0,0,不然你没法记录自己visited到哪了。同样的另外一个就是在每层dfs,你都需要知道进来的方向direction,这样你才能够知道你每次move,你走到了哪格。根据这些描述,可以得到代码如下:
public void cleanRoom(Robot robot) {
cleanRoomDFS(robot, new HashMap<>(), 0, 0, 0);
}
public void cleanRoomDFS(Robot robot, HashMap<Integer, Set<Integer>> visited, int x, int y, int direction) {
this.setVisited(visited, x, y);
robot.clean();
robot.turnLeft();
direction--;
for (int i = 0; i < 4; i++) {
int curDir = (direction + i + 4) % 4;
int newX = x + DIR[curDir][0];
int newY = y + DIR[curDir][1];
if (!this.isVisited(visited, newX, newY) && robot.move()) {
cleanRoomDFS(robot, visited, newX, newY, curDir);
robot.turnLeft();
} else {
robot.turnRight();
}
}
robot.turnLeft();
robot.move();
}
public boolean isVisited(HashMap<Integer, Set<Integer>> map, int x, int y) {
Set<Integer> visited = map.get(x);
if (visited == null) {
return false;
}
return visited.contains(y);
}
public void setVisited(HashMap<Integer, Set<Integer>> map, int x, int y) {
if (!map.containsKey(x)) {
map.put(x, new HashSet<>());
}
map.get(x).add(y);
}