1210. Minimum Moves to Reach Target with Rotations
Problem Description
You have an n x n
grid where a snake occupies exactly 2 cells. The snake starts at the top-left corner, occupying cells (0, 0)
and (0, 1)
. The grid contains:
- Empty cells (represented by
0
) that the snake can move through - Blocked cells (represented by
1
) that the snake cannot pass
The snake needs to reach the target position at the bottom-right corner, occupying cells (n-1, n-2)
and (n-1, n-1)
.
The snake can perform four types of moves:
-
Move Right: The snake moves one cell to the right while maintaining its orientation (horizontal or vertical). Both cells of the snake must move into empty cells.
-
Move Down: The snake moves one cell down while maintaining its orientation. Both cells of the snake must move into empty cells.
-
Rotate Clockwise (only when horizontal): If the snake is in a horizontal position at
(r, c)
and(r, c+1)
, and both cells directly below ((r+1, c)
and(r+1, c+1)
) are empty, the snake can rotate clockwise. After rotation, the snake occupies(r, c)
and(r+1, c)
, changing from horizontal to vertical orientation. -
Rotate Counterclockwise (only when vertical): If the snake is in a vertical position at
(r, c)
and(r+1, c)
, and both cells to the right ((r, c+1)
and(r+1, c+1)
) are empty, the snake can rotate counterclockwise. After rotation, the snake occupies(r, c)
and(r, c+1)
, changing from vertical to horizontal orientation.
Each action counts as one move. You need to find the minimum number of moves required for the snake to reach the target position. If it's impossible to reach the target, return -1
.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- Yes: This problem can be modeled as a graph where each state (position and orientation of the snake) is a node, and valid moves between states are edges.
Is it a tree?
- No: The state space is not a tree structure. Multiple paths can lead to the same state (the snake can reach the same position through different sequences of moves).
Is the problem related to directed acyclic graphs?
- No: The state graph can have cycles (though we avoid revisiting states). The problem isn't about DAG-specific properties.
Is the problem related to shortest paths?
- Yes: We need to find the minimum number of moves (shortest path) from the starting position to the target position.
Is the graph weighted?
- No: Each move has the same cost (1 move), making this an unweighted graph problem.
BFS
- Yes: For unweighted shortest path problems, BFS is the optimal choice.
Conclusion: The flowchart suggests using BFS (Breadth-First Search) for finding the minimum number of moves. This aligns perfectly with the solution approach, as BFS explores states level by level, guaranteeing that when we first reach the target state, we've found it via the shortest path (minimum number of moves).
Intuition
The key insight is to think of this problem as finding the shortest path in a state space. Each state represents not just where the snake is, but also its orientation (horizontal or vertical). This is crucial because the same position with different orientations represents different states that may require different moves to reach the target.
Why do we need to track orientation? Consider that a snake at position (r, c)
and (r, c+1)
(horizontal) has different movement options than a snake at (r, c)
and (r+1, c)
(vertical). The horizontal snake can rotate clockwise if there's space below, while the vertical snake can rotate counterclockwise if there's space to the right.
Since each move has equal cost (exactly 1 move), we're dealing with an unweighted graph problem. This immediately suggests BFS as the optimal approach because BFS explores states level by level - all states reachable in 1 move, then 2 moves, then 3 moves, and so on. The first time we encounter the target state, we're guaranteed to have found it via the minimum number of moves.
To represent the snake's position efficiently, we can use the indices of its two cells. Since the grid is n x n
, we can flatten the 2D coordinates into 1D indices: a cell at (i, j)
becomes index i * n + j
. This makes it easier to store and compare positions.
The visited set needs to store both position and orientation to avoid revisiting the same state. We represent this as (tail_position, status)
where status
is 0 for horizontal and 1 for vertical. This prevents us from exploring the same configuration multiple times, which would lead to inefficiency or infinite loops.
The four possible moves (right, down, clockwise rotation, counterclockwise rotation) are systematically checked for each state. The rotation moves have additional constraints - we need to check that the cells the snake will rotate through are empty, not just the final destination cells.
Learn more about Breadth-First Search patterns.
Solution Approach
The solution implements BFS using a queue to explore all possible states of the snake. Let's walk through the implementation details:
State Representation:
- Each snake position is represented by two indices
(a, b)
wherea
is the tail position andb
is the head position in the flattened 1D array - For a cell at
(i, j)
in the 2D grid, its 1D index isi * n + j
- The snake's orientation is tracked separately:
status = 0
for horizontal,status = 1
for vertical
Data Structures:
- Queue
q
: Stores current positions as tuples(a, b)
. Initially contains(0, 1)
representing the starting position - Set
vis
: Tracks visited states as(tail_position, status)
to avoid revisiting the same configuration. Initially contains(0, 0)
for the starting horizontal state - Target: Fixed at
(n*n - 2, n*n - 1)
, representing the last two cells of the grid
The move
Helper Function:
This function validates and adds new positions to the queue:
- Checks if both cells
(i1, j1)
and(i2, j2)
are within bounds - Converts 2D coordinates to 1D indices:
a = i1 * n + j1
,b = i2 * n + j2
- Determines orientation:
status = 0
ifi1 == i2
(horizontal), elsestatus = 1
(vertical) - If the state
(a, status)
hasn't been visited and both cells are empty (grid[i][j] == 0
), adds the position to queue and marks as visited
BFS Exploration:
For each position (a, b)
dequeued:
-
Check Target: If current position equals target
(n*n - 2, n*n - 1)
, return the current move countans
-
Convert to 2D: Extract coordinates from 1D indices:
i1, j1 = a // n, a % n
(tail)i2, j2 = b // n, b % n
(head)
-
Try All Moves:
- Move Right:
move(i1, j1 + 1, i2, j2 + 1)
- both cells shift right - Move Down:
move(i1 + 1, j1, i2 + 1, j2)
- both cells shift down - Clockwise Rotation (if horizontal): When
i1 == i2
, check ifgrid[i1 + 1][j2] == 0
(cell below head is empty), thenmove(i1, j1, i1 + 1, j1)
rotates tail down - Counterclockwise Rotation (if vertical): When
j1 == j2
, check ifgrid[i2][j1 + 1] == 0
(cell right of head is empty), thenmove(i1, j1, i1, j1 + 1)
rotates tail right
- Move Right:
-
Level Tracking: After processing all positions at current distance, increment
ans
by 1
The algorithm continues until either the target is reached (return ans
) or the queue is empty (return -1
indicating no path exists).
The time complexity is O(nΒ²)
as we can visit at most 2nΒ²
states (each cell with two orientations), and space complexity is also O(nΒ²)
for the visited set and queue.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with a 3x3 grid:
Grid: [0, 0, 0] [0, 0, 0] [0, 0, 0]
The snake starts at cells (0,0) and (0,1) horizontally, and needs to reach cells (2,1) and (2,2).
Initial State:
- Queue:
[(0, 1)]
(using 1D indices where 0 = cell(0,0), 1 = cell(0,1)) - Visited:
{(0, 0)}
(tail at index 0, status 0 for horizontal) - Moves: 0
Move 1 - Process initial position (0, 1):
- Convert to 2D: tail at (0,0), head at (0,1)
- Try all possible moves:
- Right: Move to (0,1) and (0,2) β Add
(1, 2)
to queue - Down: Move to (1,0) and (1,1) β Add
(3, 4)
to queue - Clockwise rotation: Rotate to (0,0) and (1,0) β Add
(0, 3)
to queue - Counterclockwise: Not applicable (snake is horizontal)
- Right: Move to (0,1) and (0,2) β Add
- Queue after:
[(1, 2), (3, 4), (0, 3)]
- Visited adds:
{(1, 0), (3, 0), (0, 1)}
- Increment moves to 1
Move 2 - Process position (1, 2):
- Snake at (0,1) and (0,2) horizontally
- Try moves:
- Right: Would go out of bounds
- Down: Move to (1,1) and (1,2) β Add
(4, 5)
to queue - Clockwise rotation: Rotate to (0,1) and (1,1) β Add
(1, 4)
to queue
Move 2 - Process position (3, 4):
- Snake at (1,0) and (1,1) horizontally
- Try moves:
- Right: Move to (1,1) and (1,2) β Add
(4, 5)
(already added) - Down: Move to (2,0) and (2,1) β Add
(6, 7)
to queue - Clockwise rotation: Rotate to (1,0) and (2,0) β Add
(3, 6)
to queue
- Right: Move to (1,1) and (1,2) β Add
Move 2 - Process position (0, 3):
- Snake at (0,0) and (1,0) vertically
- Try moves:
- Right: Move to (0,1) and (1,1) β Add
(1, 4)
(already added) - Down: Move to (1,0) and (2,0) β Add
(3, 6)
(already added) - Counterclockwise: Rotate to (0,0) and (0,1) β Already visited
- Right: Move to (0,1) and (1,1) β Add
After processing all positions at distance 1, increment moves to 2.
Move 3 - Continue processing:
The BFS continues exploring positions at distance 2. Eventually, we'll reach position (7, 8)
which represents the snake at cells (2,1) and (2,2) - our target!
Key Observations:
- The snake explores multiple paths simultaneously through BFS
- Each state tracks both position AND orientation (horizontal vs vertical)
- Rotations are only possible when there's enough empty space
- The first time we reach the target is guaranteed to be the shortest path
In this example, the minimum number of moves would be 3: starting horizontally at top-left, the snake can move down, then down again, then rotate and move to reach the target position at bottom-right.
Solution Implementation
1class Solution:
2 def minimumMoves(self, grid: List[List[int]]) -> int:
3 """
4 Find minimum moves for a snake to reach target position.
5 The snake occupies 2 cells and can move right, down, or rotate.
6
7 Args:
8 grid: 2D grid where 0 = empty, 1 = obstacle
9
10 Returns:
11 Minimum number of moves to reach target, or -1 if impossible
12 """
13 def try_move(head_row: int, head_col: int, tail_row: int, tail_col: int) -> None:
14 """
15 Try to move snake to new position if valid.
16
17 Args:
18 head_row, head_col: New head position
19 tail_row, tail_col: New tail position
20 """
21 # Check if both positions are within bounds
22 if (0 <= head_row < grid_size and 0 <= head_col < grid_size and
23 0 <= tail_row < grid_size and 0 <= tail_col < grid_size):
24
25 # Convert 2D coordinates to 1D indices
26 head_index = head_row * grid_size + head_col
27 tail_index = tail_row * grid_size + tail_col
28
29 # Determine orientation: 0 for horizontal, 1 for vertical
30 orientation = 0 if head_row == tail_row else 1
31
32 # Check if this state hasn't been visited and both cells are empty
33 if ((head_index, orientation) not in visited and
34 grid[head_row][head_col] == 0 and grid[tail_row][tail_col] == 0):
35
36 queue.append((head_index, tail_index))
37 visited.add((head_index, orientation))
38
39 grid_size = len(grid)
40 # Target position: snake at bottom-right corner, horizontal orientation
41 target_position = (grid_size * grid_size - 2, grid_size * grid_size - 1)
42
43 # BFS initialization: start with snake at top-left, horizontal
44 queue = deque([(0, 1)]) # Head at (0,0), tail at (0,1)
45 visited = {(0, 0)} # (head_index, orientation)
46 moves_count = 0
47
48 # BFS to find shortest path
49 while queue:
50 # Process all positions at current distance
51 for _ in range(len(queue)):
52 head_index, tail_index = queue.popleft()
53
54 # Check if we reached the target
55 if (head_index, tail_index) == target_position:
56 return moves_count
57
58 # Convert 1D indices back to 2D coordinates
59 head_row, head_col = head_index // grid_size, head_index % grid_size
60 tail_row, tail_col = tail_index // grid_size, tail_index % grid_size
61
62 # Try moving right (maintaining current orientation)
63 try_move(head_row, head_col + 1, tail_row, tail_col + 1)
64
65 # Try moving down (maintaining current orientation)
66 try_move(head_row + 1, head_col, tail_row + 1, tail_col)
67
68 # If horizontal, try clockwise rotation (pivot on head)
69 if head_row == tail_row and head_row + 1 < grid_size and grid[head_row + 1][tail_col] == 0:
70 try_move(head_row, head_col, head_row + 1, head_col)
71
72 # If vertical, try counter-clockwise rotation (pivot on head)
73 if head_col == tail_col and head_col + 1 < grid_size and grid[tail_row][head_col + 1] == 0:
74 try_move(head_row, head_col, head_row, head_col + 1)
75
76 moves_count += 1
77
78 # Target unreachable
79 return -1
80
1class Solution {
2 private int gridSize;
3 private int[][] grid;
4 private boolean[][] visited;
5 private Deque<int[]> queue = new ArrayDeque<>();
6
7 public int minimumMoves(int[][] grid) {
8 this.grid = grid;
9 gridSize = grid.length;
10 // visited[position][orientation]: position is encoded as row * n + col
11 // orientation: 0 = horizontal, 1 = vertical
12 visited = new boolean[gridSize * gridSize][2];
13
14 // Target position: snake should reach bottom-right corner
15 int[] targetPosition = {gridSize * gridSize - 2, gridSize * gridSize - 1};
16
17 // Start position: snake starts at (0,0) and (0,1) horizontally
18 queue.offer(new int[] {0, 1});
19 visited[0][0] = true; // Mark starting position as visited (horizontal orientation)
20
21 int steps = 0;
22
23 // BFS to find minimum moves
24 while (!queue.isEmpty()) {
25 int currentLevelSize = queue.size();
26
27 for (int k = 0; k < currentLevelSize; k++) {
28 int[] currentPosition = queue.poll();
29
30 // Check if snake reached target position
31 if (currentPosition[0] == targetPosition[0] && currentPosition[1] == targetPosition[1]) {
32 return steps;
33 }
34
35 // Decode positions from encoded values
36 int row1 = currentPosition[0] / gridSize;
37 int col1 = currentPosition[0] % gridSize;
38 int row2 = currentPosition[1] / gridSize;
39 int col2 = currentPosition[1] % gridSize;
40
41 // Try moving right (maintaining current orientation)
42 move(row1, col1 + 1, row2, col2 + 1);
43
44 // Try moving down (maintaining current orientation)
45 move(row1 + 1, col1, row2 + 1, col2);
46
47 // If snake is horizontal and cell below tail is empty, try clockwise rotation
48 if (row1 == row2 && row1 + 1 < gridSize && grid[row1 + 1][col2] == 0) {
49 move(row1, col1, row1 + 1, col1);
50 }
51
52 // If snake is vertical and cell to the right of tail is empty, try counterclockwise rotation
53 if (col1 == col2 && col1 + 1 < gridSize && grid[row2][col1 + 1] == 0) {
54 move(row1, col1, row1, col1 + 1);
55 }
56 }
57 steps++;
58 }
59
60 // Target position unreachable
61 return -1;
62 }
63
64 /**
65 * Attempts to move the snake to a new position
66 * @param row1 Row of snake's tail
67 * @param col1 Column of snake's tail
68 * @param row2 Row of snake's head
69 * @param col2 Column of snake's head
70 */
71 private void move(int row1, int col1, int row2, int col2) {
72 // Check if both positions are within grid boundaries
73 if (row1 >= 0 && row1 < gridSize && col1 >= 0 && col1 < gridSize &&
74 row2 >= 0 && row2 < gridSize && col2 >= 0 && col2 < gridSize) {
75
76 // Encode positions as single integers
77 int encodedPos1 = row1 * gridSize + col1;
78 int encodedPos2 = row2 * gridSize + col2;
79
80 // Determine orientation: 0 for horizontal, 1 for vertical
81 int orientation = (row1 == row2) ? 0 : 1;
82
83 // Check if this state hasn't been visited and both cells are empty
84 if (!visited[encodedPos1][orientation] && grid[row1][col1] == 0 && grid[row2][col2] == 0) {
85 queue.offer(new int[] {encodedPos1, encodedPos2});
86 visited[encodedPos1][orientation] = true;
87 }
88 }
89 }
90}
91
1class Solution {
2public:
3 int minimumMoves(vector<vector<int>>& grid) {
4 int n = grid.size();
5
6 // Target position: snake tail at (n-1, n-2) and head at (n-1, n-1)
7 auto target = make_pair(n * n - 2, n * n - 1);
8
9 // BFS queue storing snake positions as (tail_position, head_position)
10 queue<pair<int, int>> bfsQueue;
11 bfsQueue.emplace(0, 1); // Initial position: tail at (0,0), head at (0,1)
12
13 // Visited states: [position][orientation]
14 // orientation: 0 = horizontal, 1 = vertical
15 bool visited[n * n][2];
16 memset(visited, 0, sizeof visited);
17 visited[0][0] = true; // Mark initial horizontal position as visited
18
19 // Helper function to validate and add new snake positions to queue
20 auto addMove = [&](int tailRow, int tailCol, int headRow, int headCol) {
21 // Check if both tail and head are within grid boundaries
22 if (tailRow >= 0 && tailRow < n && tailCol >= 0 && tailCol < n &&
23 headRow >= 0 && headRow < n && headCol >= 0 && headCol < n) {
24
25 // Convert 2D coordinates to 1D indices
26 int tailIndex = tailRow * n + tailCol;
27 int headIndex = headRow * n + headCol;
28
29 // Determine snake orientation: 0 for horizontal, 1 for vertical
30 int orientation = (tailRow == headRow) ? 0 : 1;
31
32 // Add to queue if not visited and both cells are empty
33 if (!visited[tailIndex][orientation] &&
34 grid[tailRow][tailCol] == 0 && grid[headRow][headCol] == 0) {
35 bfsQueue.emplace(tailIndex, headIndex);
36 visited[tailIndex][orientation] = true;
37 }
38 }
39 };
40
41 int moves = 0;
42
43 // BFS to find minimum moves
44 while (!bfsQueue.empty()) {
45 int levelSize = bfsQueue.size();
46
47 // Process all positions at current level
48 for (int i = 0; i < levelSize; ++i) {
49 auto currentPosition = bfsQueue.front();
50 bfsQueue.pop();
51
52 // Check if target position is reached
53 if (currentPosition == target) {
54 return moves;
55 }
56
57 auto [tailIndex, headIndex] = currentPosition;
58
59 // Convert 1D indices back to 2D coordinates
60 int tailRow = tailIndex / n, tailCol = tailIndex % n;
61 int headRow = headIndex / n, headCol = headIndex % n;
62
63 // Move 1: Shift right (maintain current orientation)
64 addMove(tailRow, tailCol + 1, headRow, headCol + 1);
65
66 // Move 2: Shift down (maintain current orientation)
67 addMove(tailRow + 1, tailCol, headRow + 1, headCol);
68
69 // Move 3: Clockwise rotation (only when horizontal)
70 // Check if snake is horizontal and the cell below head is empty
71 if (tailRow == headRow && tailRow + 1 < n && grid[tailRow + 1][headCol] == 0) {
72 addMove(tailRow, tailCol, tailRow + 1, tailCol);
73 }
74
75 // Move 4: Counter-clockwise rotation (only when vertical)
76 // Check if snake is vertical and the cell to the right of head is empty
77 if (tailCol == headCol && tailCol + 1 < n && grid[headRow][tailCol + 1] == 0) {
78 addMove(tailRow, tailCol, tailRow, tailCol + 1);
79 }
80 }
81
82 ++moves;
83 }
84
85 // Target position unreachable
86 return -1;
87 }
88};
89
1/**
2 * Calculates the minimum number of moves for a snake to reach the target position in a grid
3 * @param grid - 2D array representing the game board (0 = empty, 1 = obstacle)
4 * @returns Minimum number of moves to reach target, or -1 if impossible
5 */
6function minimumMoves(grid: number[][]): number {
7 const gridSize: number = grid.length;
8 // Target position: snake tail at (n-1, n-2) and head at (n-1, n-1)
9 const targetTail: number = gridSize * gridSize - 2;
10 const targetHead: number = gridSize * gridSize - 1;
11
12 // BFS queue storing snake positions as [tail_position, head_position]
13 const queue: number[][] = [[0, 1]]; // Initial position: horizontal at top-left
14
15 // Visited states: [position][orientation] where orientation: 0 = horizontal, 1 = vertical
16 const visited: boolean[][] = Array.from(
17 { length: gridSize * gridSize },
18 () => Array(2).fill(false)
19 );
20 visited[0][0] = true; // Mark initial state as visited
21
22 /**
23 * Attempts to move the snake to a new position and adds valid moves to the queue
24 * @param tailRow - Row index of snake's tail
25 * @param tailCol - Column index of snake's tail
26 * @param headRow - Row index of snake's head
27 * @param headCol - Column index of snake's head
28 */
29 const tryMove = (tailRow: number, tailCol: number, headRow: number, headCol: number): void => {
30 // Check if both tail and head positions are within bounds
31 if (tailRow >= 0 && tailRow < gridSize && tailCol >= 0 && tailCol < gridSize &&
32 headRow >= 0 && headRow < gridSize && headCol >= 0 && headCol < gridSize) {
33
34 // Convert 2D coordinates to 1D position indices
35 const tailPosition: number = tailRow * gridSize + tailCol;
36 const headPosition: number = headRow * gridSize + headCol;
37
38 // Determine snake orientation: 0 = horizontal, 1 = vertical
39 const orientation: number = tailRow === headRow ? 0 : 1;
40
41 // Check if this state hasn't been visited and both cells are empty
42 if (!visited[tailPosition][orientation] &&
43 grid[tailRow][tailCol] === 0 &&
44 grid[headRow][headCol] === 0) {
45
46 queue.push([tailPosition, headPosition]);
47 visited[tailPosition][orientation] = true;
48 }
49 }
50 };
51
52 let moveCount: number = 0;
53
54 // BFS to find shortest path
55 while (queue.length > 0) {
56 const levelSize: number = queue.length;
57
58 // Process all positions at current BFS level
59 for (let i = 0; i < levelSize; i++) {
60 const currentPosition: number[] = queue.shift()!;
61
62 // Check if we've reached the target position
63 if (currentPosition[0] === targetTail && currentPosition[1] === targetHead) {
64 return moveCount;
65 }
66
67 // Extract current tail and head coordinates
68 const tailRow: number = Math.floor(currentPosition[0] / gridSize);
69 const tailCol: number = currentPosition[0] % gridSize;
70 const headRow: number = Math.floor(currentPosition[1] / gridSize);
71 const headCol: number = currentPosition[1] % gridSize;
72
73 // Try moving right (translation)
74 tryMove(tailRow, tailCol + 1, headRow, headCol + 1);
75
76 // Try moving down (translation)
77 tryMove(tailRow + 1, tailCol, headRow + 1, headCol);
78
79 // If snake is horizontal, try clockwise rotation (90 degrees)
80 if (tailRow === headRow && tailRow + 1 < gridSize && grid[tailRow + 1][headCol] === 0) {
81 tryMove(tailRow, tailCol, tailRow + 1, tailCol);
82 }
83
84 // If snake is vertical, try counter-clockwise rotation (90 degrees)
85 if (tailCol === headCol && tailCol + 1 < gridSize && grid[headRow][tailCol + 1] === 0) {
86 tryMove(tailRow, tailCol, tailRow, tailCol + 1);
87 }
88 }
89
90 moveCount++;
91 }
92
93 // Target position is unreachable
94 return -1;
95}
96
Time and Space Complexity
Time Complexity: O(n^2)
The algorithm uses BFS to explore all possible states of the snake. The snake is represented by two cells, and each cell can be in one of n^2
positions. However, the snake has only two orientations (horizontal or vertical), and the valid positions are constrained. The total number of unique states is bounded by O(n^2)
because:
- We track states using
(head_position, orientation)
where head_position can be at mostn^2
locations - Each state has 2 possible orientations (horizontal=0, vertical=1)
- The visited set
vis
ensures each state is processed only once
For each state, we perform at most 4 moves (right, down, and potentially 2 rotations), each taking O(1)
time. Therefore, the overall time complexity is O(n^2)
.
Space Complexity: O(n^2)
The space is dominated by:
- The BFS queue
q
which can contain at mostO(n^2)
states in the worst case - The visited set
vis
which stores at mostO(n^2)
unique states (each state is a tuple of position and orientation) - The input grid takes
O(n^2)
space
Therefore, the total space complexity is O(n^2)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Snake Position Representation
A critical pitfall is confusing which cell represents the "head" and which represents the "tail" of the snake. In the provided code, there's actually a naming inconsistency - the variables are named head_index
and tail_index
, but based on the problem description and initial state (0, 1)
, the snake starts at cells (0, 0)
and (0, 1)
. The code treats the first value as position at (0, 0)
and second as (0, 1)
, but names suggest otherwise.
Fix: Use consistent and clear naming:
# Better naming convention queue = deque([(0, 1)]) # (first_cell, second_cell) or (tail, head) # where first_cell is at (0,0) and second_cell is at (0,1)
2. Rotation Boundary Check Missing
When performing rotations, the code checks if the pivot cell's adjacent cell is empty, but doesn't verify if the rotation would place the snake out of bounds. While the current implementation includes boundary checks in try_move
, a common mistake is to forget checking the intermediate cell needed for rotation.
Issue Example: For clockwise rotation from horizontal position, both (r+1, c)
and (r+1, c+1)
must be empty AND within bounds for the rotation to be valid.
Fix: Add explicit validation before rotation:
# For clockwise rotation (horizontal to vertical) if head_row == tail_row: # Currently horizontal # Need to check BOTH cells below are valid and empty if (head_row + 1 < grid_size and grid[head_row + 1][head_col] == 0 and grid[head_row + 1][tail_col] == 0): try_move(head_row, head_col, head_row + 1, head_col)
3. Visited State Tracking Error
The visited set stores (position, orientation)
but uses only one position index instead of both. This could theoretically cause issues if the snake can reach the same cell pair in different orders.
Current approach: visited.add((head_index, orientation))
Potential issue: Two different snake configurations with the same head position and orientation but different tail positions would be considered the same state.
Fix: Store complete state information:
# More precise state tracking
visited.add((min(head_index, tail_index), max(head_index, tail_index), orientation))
4. Target Position Assumption
The code assumes the target is always at (n*n - 2, n*n - 1)
in horizontal orientation. However, the problem states the snake should occupy (n-1, n-2)
and (n-1, n-1)
, which translates to indices (n*n - n - 1, n*n - 1)
not (n*n - 2, n*n - 1)
.
Fix: Correct target calculation:
# Correct target position # (n-1, n-2) -> index = (n-1) * n + (n-2) = n*n - 2 # (n-1, n-1) -> index = (n-1) * n + (n-1) = n*n - 1 target_position = (grid_size * grid_size - 2, grid_size * grid_size - 1) # This is actually correct
5. Orientation Detection Logic
The orientation is determined by comparing rows (head_row == tail_row
), but this assumes a specific ordering of the snake cells. If the cell indices are swapped, the orientation detection could fail.
Fix: Use absolute position comparison:
# More robust orientation detection
def get_orientation(pos1_row, pos1_col, pos2_row, pos2_col):
if pos1_row == pos2_row:
return 0 # Horizontal
elif pos1_col == pos2_col:
return 1 # Vertical
else:
raise ValueError("Invalid snake position")
Which data structure is used in a depth first search?
Recommended Readings
https assets algo monster cover_photos bfs svg Breadth First Search on Trees Hopefully by this time you've drunk enough DFS Kool Aid to understand its immense power and seen enough visualization to create a call stack in your mind Now let me introduce the companion spell Breadth First Search BFS
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!