题目地址:
https://leetcode.com/problems/robot-room-cleaner/
给定一个机器人清洁器的类,其能实现的方法如下:
interface Robot {
// returns true if next cell is open and robot moves into the cell.
// returns false if next cell is obstacle and robot stays on the current cell.
boolean move();
// Robot will stay on the same cell after calling turnLeft/turnRight.
// Each turn will be 90 degrees.
void turnLeft();
void turnRight();
// Clean the current cell.
void clean();
}
现在该清洁器位于某个 m × n m\times n m×n的网格内,要求将该网格内所有能清洁的位置都做清洁,网格可能有障碍物和边界,该机器人只需要将自己所在的连通块清洁完成即可。
思路是DFS。每次在一个位置的时候,先清理之,再标记一下该位置为访问过,接下来开始以一定的顺序遍历 4 4 4个方向(比如上、右、下、左这样的顺序),然后如果某个方向可以走,则走进去继续DFS;如果走不了,则顺时针旋转 90 ° 90\degree 90°,接着沿下一个方向DFS。如果四个方向都走不了了,则DFS要回溯,清洁器的位置和方向也需要恢复到上一层DFS的状态。代码如下:
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Solution {
class Pair {
private int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
Pair pair = (Pair) o;
return x == pair.x && y == pair.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
public void cleanRoom(Robot robot) {
dfs(0, 0, new HashSet<>(), 0, new int[]{-1, 0, 1, 0, -1}, robot);
}
private void dfs(int x, int y, Set<Pair> vis, int dir, int[] d, Robot robot) {
vis.add(new Pair(x, y));
robot.clean();
// 四个方向依次是顺时针转90°的关系
for (int i = 0; i < 4; i++) {
int nextDir = (dir + i) % 4;
int nextX = x + d[nextDir], nextY = y + d[nextDir + 1];
Pair next = new Pair(nextX, nextY);
// 注意这里一定要先判断之前有没有走过,再判断能不能走,
// 因为有的位置即使能走,但之前走过了,现在也不应该走
if (!vis.contains(next) && robot.move()) {
dfs(nextX, nextY, vis, nextDir, d, robot);
reset(robot);
}
// 顺时针转90°接着遍历下一个方向
robot.turnRight();
}
}
// 回溯的时候要恢复现场,恢复现场不但要位置回退,方向也要变成最初的方向
private void reset(Robot robot) {
robot.turnRight();
robot.turnRight();
robot.move();
robot.turnRight();
robot.turnRight();
}
}
时空复杂度 O ( m n ) O(mn) O(mn)。