3248. Snake in Matrix
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
.
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:
- Each command directly translates to a simple coordinate change
- We avoid repeated multiplication and division operations during movement
- 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:
-
Initialize position variables: Set
x = 0
andy = 0
to represent the starting position. -
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
- For
-
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 EvaluatorExample 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:
-
Initial state: Snake starts at cell 0
- Position:
x = 0
(row),y = 0
(column) - Current cell: 0
- Position:
-
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
- Check first character:
-
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
- Check first character:
-
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
- Check first character:
-
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
- Check first character:
-
Calculate final cell number:
- Formula:
cell_number = x * n + y
- Result:
2 * 3 + 0 = 6
- Formula:
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.
Which data structure is used in a depth first search?
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!