A width x height
grid is on an XY-plane with the bottom-left cell at (0, 0)
and the top-right cell at (width - 1, height - 1)
. The grid is aligned with the four cardinal directions ("North"
, "East"
, "South"
, and "West"
). A robot is initially at cell (0, 0)
facing direction "East"
.
The robot can be instructed to move for a specific number of steps. For each step, it does the following.
After the robot finishes moving the number of steps required, it stops and awaits the next instruction.
Implement the Robot
class:
Robot(int width, int height)
Initializes the width x height
grid with the robot at (0, 0)
facing "East"
.void step(int num)
Instructs the robot to move forward num
steps.int[] getPos()
Returns the current cell the robot is at, as an array of length 2, [x, y]
.String getDir()
Returns the current direction of the robot, "North"
, "East"
, "South"
, or "West"
.Example 1:
Input ["Robot", "step", "step", "getPos", "getDir", "step", "step", "step", "getPos", "getDir"] [[6, 3], [2], [2], [], [], [2], [1], [4], [], []] Output [null, null, null, [4, 0], "East", null, null, null, [1, 2], "West"] Explanation Robot robot = new Robot(6, 3); // Initialize the grid and the robot at (0, 0) facing East. robot.step(2); // It moves two steps East to (2, 0), and faces East. robot.step(2); // It moves two steps East to (4, 0), and faces East. robot.getPos(); // return [4, 0] robot.getDir(); // return "East" robot.step(2); // It moves one step East to (5, 0), and faces East. // Moving the next step East would be out of bounds, so it turns and faces North. // Then, it moves one step North to (5, 1), and faces North. robot.step(1); // It moves one step North to (5, 2), and faces North (not West). robot.step(4); // Moving the next step North would be out of bounds, so it turns and faces West. // Then, it moves four steps West to (1, 2), and faces West. robot.getPos(); // return [1, 2] robot.getDir(); // return "West"
Constraints:
2 <= width, height <= 100
1 <= num <= 105
104
calls in total will be made to step
, getPos
, and getDir
.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:
Imagine a robot walking around a rectangular grid. The brute force approach simulates the robot's movement step by step for every possible command it receives. It meticulously tracks the robot's position after each move to figure out where it ends up.
Here's how the algorithm would work step-by-step:
class WalkingRobotSimulationII:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
self.current_position_x = 0
self.current_position_y = 0
self.direction_index = 0 # 0: East, 1: North, 2: West, 3: South
self.directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
def step(self, number_of_steps: int) -> None:
for _ in range(number_of_steps):
next_position_x = self.current_position_x + self.directions[self.direction_index][0]
next_position_y = self.current_position_y + self.directions[self.direction_index][1]
# Determine if next step is valid and move or rotate if invalid
if 0 <= next_position_x < self.width and 0 <= next_position_y < self.height:
self.current_position_x = next_position_x
self.current_position_y = next_position_y
else:
self.direction_index = (self.direction_index + 1) % 4
next_position_x = self.current_position_x + self.directions[self.direction_index][0]
next_position_y = self.current_position_y + self.directions[self.direction_index][1]
if 0 <= next_position_x < self.width and 0 <= next_position_y < self.height:
self.current_position_x = next_position_x
self.current_position_y = next_position_y
#Handle edge case where robot may be in a corner
else:
break
def getPos(self) -> list[int]:
return [self.current_position_x, self.current_position_y]
def getDir(self) -> str:
# Map direction index to string representation
if self.direction_index == 0:
return "East"
elif self.direction_index == 1:
return "North"
elif self.direction_index == 2:
return "West"
# If all the above checks failed then return South as direction
else:
return "South"
The robot moves along the perimeter of a rectangular grid. We can simulate this movement efficiently by thinking of the perimeter as a cycle and tracking the robot's position along it, rather than directly updating its coordinates after each move. This avoids repeating calculations and improves performance.
Here's how the algorithm would work step-by-step:
class WalkingRobot:
def __init__(self, width: int, height: int):
self.width_limit = width
self.height_limit = height
self.current_x = 0
self.current_y = 0
self.direction_index = 0
self.directions = ["East", "North", "West", "South"]
# Calculate the perimeter of the rectangle
self.perimeter = 2 * (width + height) - 4
self.current_position = 0
def step(self, number_of_steps: int) -> None:
# Normalize steps to account for looping around the perimeter.
number_of_steps %= self.perimeter
self.current_position = (self.current_position + number_of_steps) % self.perimeter
current_width = self.width_limit - 1
current_height = self.height_limit - 1
if self.current_position <= current_width:
self.current_x = self.current_position
self.current_y = 0
self.direction_index = 0
elif self.current_position <= current_width + current_height:
# Determine position on the north side.
self.current_x = current_width
self.current_y = self.current_position - current_width
self.direction_index = 1
elif self.current_position <= current_width * 2 + current_height:
self.current_x = current_width - (self.current_position - (current_width + current_height))
self.current_y = current_height
self.direction_index = 2
else:
# Calculate the remaining distance to find the y-coordinate.
self.current_x = 0
self.current_y = current_height - (self.current_position - (2 * current_width + current_height))
self.direction_index = 3
def getPos(self) -> list[int]:
return [self.current_x, self.current_y]
def getDir(self) -> str:
return self.directions[self.direction_index]
Case | How to Handle |
---|---|
Zero width or height in constructor | The constructor should probably throw an exception or error if either dimension is zero as the robot cannot move. |
Single step causes robot to complete a full loop | Modulo operations and current direction tracking should correctly handle complete loops without issues. |
Large width and height values leading to integer overflow during distance calculations | Ensure that the data type used for distance calculations (perimeter) is large enough to prevent overflow (e.g., long in Java/C++). |
Multiple consecutive calls to move() results in several full loops | The code should appropriately use the modulo operator to manage large step counts and wrap around the perimeter accurately. |
Initial direction is not NORTH, EAST, SOUTH, or WEST | The direction should be properly initialized and checked in the constructor, setting to a default if an invalid direction is provided. |
Empty path (width=1, height=1) | If width=1 and height=1, define an appropriate boundary and edge case to avoid infinite recursion. |
Move() called after the robot has been fully around the perimeter. | The remainder operator in move should handle this correctly allowing the robot to retrace the same path. |
Very large number of move calls with relatively small width/height | The modulo operator used when computing the remaining steps should avoid performance degradation with an extremely large number of moves. |