Facebook Pixel

3248. Snake in Matrix

EasyArrayStringSimulation
Leetcode Link

Problem Description

You have a snake moving on an n x n grid. Each cell in the grid has a unique identifier calculated as grid[i][j] = (i * n) + j, where i is the row number and j is the column number.

The snake starts at cell 0 (which is position grid[0][0]) and moves according to a sequence of commands. The snake can move in four directions:

  • "UP" - moves one row up
  • "DOWN" - moves one row down
  • "LEFT" - moves one column left
  • "RIGHT" - moves one column right

You're given:

  • An integer n representing the grid size (n x n)
  • An array of strings commands where each command tells the snake which direction to move

The problem guarantees that the snake will always stay within the grid boundaries.

Your task is to find the final cell position (as a number) where the snake ends up after executing all the commands.

For example, in a 3x3 grid, the cells are numbered:

0  1  2
3  4  5
6  7  8

If the snake starts at cell 0 and moves RIGHT, it goes to cell 1. If it then moves DOWN, it goes to cell 4. The final position would be 4.

The solution tracks the snake's position using row (x) and column (y) coordinates, updates them based on each command, and calculates the final cell number using the formula x * n + y.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that we don't need to track the entire grid or the snake's path - we only care about where the snake ends up. Since each move is independent and simply shifts the snake's position by one cell in a specific direction, we can track the final position using coordinates.

Think of the grid positions as a 2D coordinate system where each cell can be identified by its row and column. The snake starts at row 0, column 0. When it moves:

  • UP means row decreases by 1
  • DOWN means row increases by 1
  • LEFT means column decreases by 1
  • RIGHT means column increases by 1

Instead of converting between cell numbers and coordinates repeatedly, we can work entirely in the coordinate system and only convert to the cell number at the end. This is more efficient because:

  1. Each command directly translates to a simple coordinate change
  2. We avoid repeated multiplication and division operations during movement
  3. The final conversion uses the formula cell_number = row * n + column

The formula row * n + column works because in a grid numbered from 0, each row contains exactly n cells. So to get to row i, we skip i * n cells, then add the column offset j to reach the exact cell.

This approach is straightforward - we simulate the movement by tracking coordinates, then convert once at the end. We don't need complex data structures or to remember the path taken, just the cumulative effect of all moves on the snake's position.

Solution Approach

We implement a simulation approach by tracking the snake's position using two variables x and y representing the row and column coordinates respectively. Both start at 0 since the snake begins at cell 0 (position [0, 0]).

The implementation follows these steps:

  1. Initialize position variables: Set x = 0 and y = 0 to represent the starting position.

  2. Process each command: Iterate through the commands array and update the coordinates based on the direction:

    • For "UP": Decrease row by 1 → x -= 1
    • For "DOWN": Increase row by 1 → x += 1
    • For "LEFT": Decrease column by 1 → y -= 1
    • For "RIGHT": Increase column by 1 → y += 1
  3. Convert to cell number: After processing all commands, calculate the final cell position using the formula x * n + y.

The solution uses a pattern matching approach (Python's match statement) to cleanly handle the four possible commands. By checking only the first character of each command (c[0]), we can distinguish between:

  • "U" for UP
  • "D" for DOWN
  • "L" for LEFT
  • "R" for RIGHT

This optimization avoids comparing entire strings, making the code more efficient.

The time complexity is O(m) where m is the number of commands, as we process each command exactly once. The space complexity is O(1) since we only use two variables to track the position regardless of input size.

The formula x * n + y works because in an n x n grid numbered from 0, each row contains exactly n cells. To reach row x, we skip x * n cells, then add y to reach the specific column within that row.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example with a 3×3 grid where n = 3.

The grid cells are numbered as:

0  1  2
3  4  5
6  7  8

Given: n = 3, commands = ["RIGHT", "DOWN", "LEFT", "DOWN"]

Step-by-step simulation:

  1. Initial state: Snake starts at cell 0

    • Position: x = 0 (row), y = 0 (column)
    • Current cell: 0
  2. Command 1: "RIGHT"

    • Check first character: "R" → move right
    • Update: y = y + 1 = 0 + 1 = 1
    • New position: x = 0, y = 1
    • Snake moves from cell 0 to cell 1
  3. Command 2: "DOWN"

    • Check first character: "D" → move down
    • Update: x = x + 1 = 0 + 1 = 1
    • New position: x = 1, y = 1
    • Snake moves from cell 1 to cell 4
  4. Command 3: "LEFT"

    • Check first character: "L" → move left
    • Update: y = y - 1 = 1 - 1 = 0
    • New position: x = 1, y = 0
    • Snake moves from cell 4 to cell 3
  5. Command 4: "DOWN"

    • Check first character: "D" → move down
    • Update: x = x + 1 = 1 + 1 = 2
    • New position: x = 2, y = 0
    • Snake moves from cell 3 to cell 6
  6. Calculate final cell number:

    • Formula: cell_number = x * n + y
    • Result: 2 * 3 + 0 = 6

Visual path representation:

[0]→ 1   2     (After RIGHT)
 3  [4]  5     (After DOWN)
[3]  4   5     (After LEFT)
 6   7   8     (After DOWN)
[6]

The snake ends at cell 6, which matches our calculation. This demonstrates how tracking coordinates (x, y) and converting only at the end is more efficient than converting between cell numbers and coordinates for each move.

Solution Implementation

1class Solution:
2    def finalPositionOfSnake(self, n: int, commands: List[str]) -> int:
3        # Initialize starting position at (0, 0)
4        # row represents the current row position
5        # col represents the current column position
6        row = 0
7        col = 0
8      
9        # Process each command to update the snake's position
10        for command in commands:
11            # Check the first character of the command to determine direction
12            if command[0] == "U":
13                # Move up: decrease row by 1
14                row -= 1
15            elif command[0] == "D":
16                # Move down: increase row by 1
17                row += 1
18            elif command[0] == "L":
19                # Move left: decrease column by 1
20                col -= 1
21            elif command[0] == "R":
22                # Move right: increase column by 1
23                col += 1
24      
25        # Convert 2D position to 1D index
26        # Formula: row * n + col (where n is the grid width)
27        return row * n + col
28
1class Solution {
2    /**
3     * Calculates the final position of a snake on an n x n grid after executing a series of commands.
4     * The snake starts at position (0, 0) and moves according to the given commands.
5     * 
6     * @param n The size of the n x n grid
7     * @param commands List of movement commands ("UP", "DOWN", "LEFT", "RIGHT")
8     * @return The final position as a single integer (row * n + column)
9     */
10    public int finalPositionOfSnake(int n, List<String> commands) {
11        // Initialize starting position at (0, 0)
12        int row = 0;
13        int column = 0;
14      
15        // Process each command in the list
16        for (String command : commands) {
17            // Get the first character of the command to determine direction
18            char direction = command.charAt(0);
19          
20            // Update position based on the direction
21            switch (direction) {
22                case 'U':  // Move up: decrease row index
23                    row--;
24                    break;
25                case 'D':  // Move down: increase row index
26                    row++;
27                    break;
28                case 'L':  // Move left: decrease column index
29                    column--;
30                    break;
31                case 'R':  // Move right: increase column index
32                    column++;
33                    break;
34            }
35        }
36      
37        // Convert 2D position to 1D index using formula: row * n + column
38        return row * n + column;
39    }
40}
41
1class Solution {
2public:
3    int finalPositionOfSnake(int n, vector<string>& commands) {
4        // Initialize starting position at (0, 0)
5        // row represents the current row position
6        // col represents the current column position
7        int row = 0;
8        int col = 0;
9      
10        // Process each command in the commands vector
11        for (const auto& command : commands) {
12            // Check the first character of the command to determine direction
13            switch (command[0]) {
14                case 'U':  // Move up: decrease row index
15                    row--;
16                    break;
17                case 'D':  // Move down: increase row index
18                    row++;
19                    break;
20                case 'L':  // Move left: decrease column index
21                    col--;
22                    break;
23                case 'R':  // Move right: increase column index
24                    col++;
25                    break;
26            }
27        }
28      
29        // Convert 2D position to 1D index in n×n grid
30        // Formula: row * n + col gives the position in a flattened array
31        return row * n + col;
32    }
33};
34
1/**
2 * Calculates the final position of a snake on an n×n grid after executing a series of commands.
3 * The snake starts at position (0, 0) and moves according to the given commands.
4 * 
5 * @param n - The size of the square grid (n×n)
6 * @param commands - Array of movement commands where each command is a string starting with:
7 *                   'U' for up (row decreases), 'D' for down (row increases),
8 *                   'L' for left (column decreases), 'R' for right (column increases)
9 * @returns The final position as a single integer value (row * n + column)
10 */
11function finalPositionOfSnake(n: number, commands: string[]): number {
12    // Initialize starting position at top-left corner (0, 0)
13    let row: number = 0;
14    let column: number = 0;
15  
16    // Process each command to update the snake's position
17    for (const command of commands) {
18        // Get the first character of the command to determine direction
19        const direction: string = command[0];
20      
21        // Update position based on the direction
22        if (direction === 'U') {
23            row--; // Move up: decrease row index
24        } else if (direction === 'D') {
25            row++; // Move down: increase row index
26        } else if (direction === 'L') {
27            column--; // Move left: decrease column index
28        } else if (direction === 'R') {
29            column++; // Move right: increase column index
30        }
31    }
32  
33    // Convert 2D position to 1D index using row-major order
34    return row * n + column;
35}
36

Time and Space Complexity

The time complexity is O(m), where m is the length of the array commands. The algorithm iterates through each command exactly once, performing constant-time operations (pattern matching and arithmetic operations) for each command.

The space complexity is O(1). The algorithm only uses a fixed amount of extra space for the variables x and y to track the snake's position, regardless of the input size. No additional data structures that grow with the input are created.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Confusing Row/Column with X/Y Coordinates

A frequent mistake is mixing up the coordinate system. Many developers instinctively think of x as horizontal (columns) and y as vertical (rows), which is the opposite of the matrix indexing convention where the first index is the row (vertical) and the second is the column (horizontal).

Incorrect approach:

x = 0  # thinking this is column
y = 0  # thinking this is row

for command in commands:
    if command[0] == "U":
        y -= 1  # Wrong: moving up should affect row, not what we think is x
    elif command[0] == "R":
        x += 1  # This would be correct if x was column
      
return y * n + x  # Formula would be backwards

Solution: Use clear variable names like row and col instead of x and y to avoid confusion.

2. Incorrect Direction Mapping

Another common error is incorrectly mapping the direction to coordinate changes, particularly confusing which operations should increment vs decrement.

Incorrect approach:

if command[0] == "U":
    row += 1  # Wrong: UP should decrease row (move to smaller row index)
elif command[0] == "D":
    row -= 1  # Wrong: DOWN should increase row

Solution: Remember that in a grid indexed from top-left:

  • UP means moving to a smaller row index (row - 1)
  • DOWN means moving to a larger row index (row + 1)
  • LEFT means moving to a smaller column index (col - 1)
  • RIGHT means moving to a larger column index (col + 1)

3. Using Wrong Formula for Cell Calculation

Developers might incorrectly calculate the final cell position by using the wrong formula or swapping the components.

Incorrect approaches:

# Wrong: Adding instead of multiplying
return row + n + col

# Wrong: Swapping row and column in formula
return col * n + row

# Wrong: Using n-1 instead of n
return row * (n-1) + col

Solution: The correct formula is row * n + col. This works because each row contains exactly n cells, so to reach row r, we skip r * n cells, then add the column offset.

4. Not Handling Edge Cases in String Comparison

While the problem guarantees valid commands, comparing full strings or using incorrect string methods can lead to issues.

Potentially problematic approach:

if command == "UP":  # Works but less efficient
    row -= 1
elif command.startswith("U"):  # Overkill for single character check
    row -= 1
elif command[0:1] == "U":  # Creates unnecessary substring
    row -= 1

Solution: Simply check the first character using command[0] for efficiency and clarity. This approach is both faster and cleaner since all commands start with unique letters.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used in a depth first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More