You're given a room that a robot needs to clean. The room is conceptually a grid, but the robot doesn't know the dimensions or layout beforehand. The robot can:
move()
: Attempts to move one cell forward in its current direction. Returns true
if the move was successful (the cell is clean and not blocked), and false
otherwise.turnLeft()
: Turns the robot 90 degrees to the left.turnRight()
: Turns the robot 90 degrees to the right.clean()
: Cleans the current cell.The robot starts at an unknown location within the room, facing an unknown direction. The room may contain obstacles.
Your task is to write an algorithm to clean every reachable cell in the room.
Example:
Imagine a simple 3x3 room where the robot starts in the center, and there's an obstacle to the north.
_ _ _
|_|_|_|
|_|R|_|
|_|_|_|
The robot (R) must traverse and clean all the _
cells. If the top-middle cell was an obstacle, the robot's move()
function would return false
if it attempted to move north from the center cell. However, the robot must still navigate to all other available cells.
Constraints:
Write a function cleanRoom(robot)
that takes the robot
object as input and instructs the robot to clean the entire room.
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. |