You are controlling a robot that is cleaning a room. The room is represented as a grid where each cell is either clean or blocked. The robot starts at an unknown location in the room and faces an unknown direction. You need to write an algorithm to clean the entire room, meaning visiting every clean cell at least once.
The robot has the following API:
bool move()
: Attempts to move the robot one cell forward. Returns true
if the move was successful (the cell is clean and unvisited), and false
otherwise (the cell is blocked or already visited).void turnLeft()
: Turns the robot 90 degrees to the left.void turnRight()
: Turns the robot 90 degrees to the right.void clean()
: Cleans the current cell.Note:
move()
function will return false
if it tries to move into a blocked cell or outside the grid.Example:
Consider a room represented by a grid:
1 1 1 1 1
1 0 1 0 1
1 1 1 1 1
Where 1
represents a clean cell and 0
represents a blocked cell. The robot starts at an unknown location (e.g., (1, 0)) and faces an unknown direction (e.g., right). Your algorithm should ensure that the robot visits all the 1
cells and cleans them.
Constraints:
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The robot needs to clean every room. The brute force method makes the robot try every possible path, moving forward, turning, and backtracking until it has explored everywhere it can possibly go. It's like trying every single maze solution until one works.
Here's how the algorithm would work step-by-step:
def robot_room_cleaner_brute_force(robot):
visited_cells = set()
current_direction = 0 # 0: up, 1: right, 2: down, 3: left
current_row = 0
current_col = 0
def move_forward():
nonlocal current_row, current_col
if current_direction == 0:
current_row -= 1
elif current_direction == 1:
current_col += 1
elif current_direction == 2:
current_row += 1
else:
current_col -= 1
def move_back():
nonlocal current_row, current_col
if current_direction == 0:
current_row += 1
elif current_direction == 1:
current_col -= 1
elif current_direction == 2:
current_row -= 1
else:
current_col += 1
def get_current_cell():
return (current_row, current_col)
while True:
current_cell = get_current_cell()
if current_cell not in visited_cells:
robot.clean()
visited_cells.add(current_cell)
can_move_forward = robot.move()
if can_move_forward:
move_forward()
continue
else:
# Try all directions by turning right
turned_count = 0
while turned_count < 4:
robot.turn_right()
current_direction = (current_direction + 1) % 4
turned_count += 1
can_move_forward = robot.move()
if can_move_forward:
move_forward()
break
# If we can't move anywhere, backtrack
if turned_count == 4:
move_back()
robot.turn_right()
robot.turn_right()
if not robot.move():
break
move_forward()
robot.turn_right()
robot.turn_right()
all_cleaned = True
for row_delta in range(-10, 11):
for col_delta in range(-10, 11):
test_row = current_row + row_delta
test_col = current_col + col_delta
if (test_row, test_col) not in visited_cells and robot.is_valid_move(row_delta, col_delta):
all_cleaned = False
break
if not all_cleaned:
break
if all_cleaned and not can_move_forward:
break
return list(visited_cells)
The problem involves simulating a robot cleaning a room. Instead of exhaustively exploring every possible path, the efficient solution relies on a depth-first search strategy combined with backtracking to systematically explore the room and ensure complete cleaning.
Here's how the algorithm would work step-by-step:
class Robot:
def move(self):
return True
def turn_left(self):
return
def turn_right(self):
return
def clean(self):
return
def clean_room(robot):
visited = set()
# Directions: up, right, down, left
directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
def go_back():
robot.turn_right()
robot.turn_right()
robot.move()
robot.turn_right()
robot.turn_right()
def explore(row, col, current_direction):
visited.add((row, col))
robot.clean()
for index in range(4):
new_direction = (current_direction + index) % 4
new_row = row + directions[new_direction][0]
new_col = col + directions[new_direction][1]
#Avoid exploring already cleaned or obstacle cells
if (new_row, new_col) not in visited:
robot.turn_right()
if robot.move():
# Explore in the new direction.
explore(new_row, new_col, new_direction)
# Backtrack after exploring the new direction.
go_back()
explore(0, 0, 0)
Case | How to Handle |
---|---|
Null or empty room (no cells) | The base case for the recursion should immediately return, avoiding any processing. |
Room with a single cell | The robot cleans it and returns without any further movements. |
Room is a straight line (1xn or nx1) | The algorithm should handle this by moving along the line, cleaning each cell, and turning around at the end if necessary. |
Room is a fully walled-in space (no exits) | The robot might get stuck in the initial cell if it cannot move, requiring a check for this and immediate termination. |
Robot starts in a dirty cell with no cleanable adjacent cells | The robot cleans the current cell and algorithm will backtrack immediately as there is nowhere else to go. |
Circular room layout where returning to the starting cell doesn't indicate full exploration | Maintain a set of visited cells to avoid infinite loops and ensure full exploration, regardless of cyclic paths. |
Integer overflow in distance calculations (if applicable) | Use appropriate data types to prevent overflow (e.g., long) or ensure calculations are done in a way that prevents overflow. |
Maximum recursion depth exceeded for very large rooms | While unlikely given reasonable room sizes, consider iterative solution instead of recursive or implement tail-call optimization. |