Facebook Pixel

2120. Execution of All Suffix Instructions Staying in a Grid

MediumStringSimulation
Leetcode Link

Problem Description

You have an n x n grid where cells are indexed from (0, 0) at the top-left to (n-1, n-1) at the bottom-right. A robot starts at position startPos = [startRow, startCol].

You're given a string s of length m containing movement instructions:

  • 'L' - move left (decrease column by 1)
  • 'R' - move right (increase column by 1)
  • 'U' - move up (decrease row by 1)
  • 'D' - move down (increase row by 1)

The key twist is that the robot can start executing from any position i in the instruction string (not just from the beginning). When starting from position i, the robot:

  1. Executes instructions sequentially from index i to the end of string s
  2. Stops if the next instruction would move it outside the grid boundaries
  3. Stops when there are no more instructions left

Your task is to return an array answer of length m, where answer[i] represents the total number of instructions the robot can successfully execute when starting from the i-th instruction in string s.

For example, if n = 3, startPos = [0, 1], and s = "RRDDLU":

  • Starting from index 0: The robot might execute several moves before hitting a boundary or finishing all instructions
  • Starting from index 1: The robot begins with the second 'R' and continues from there
  • And so on for each starting position

The solution simulates each possible starting position by:

  1. Iterating through each index i as a potential starting point
  2. From position i, attempting to execute each subsequent instruction
  3. Checking if each move keeps the robot within the grid bounds [0, n-1]
  4. Counting valid moves until either hitting a boundary or reaching the end of instructions
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to find how many instructions can be executed from each possible starting position in the instruction string. This naturally suggests a simulation approach - we need to actually try starting from each position and see how far we can go.

Think of it like testing different "entry points" into a sequence of directions. If you have a path like "go right, right, down, down, left, up", you want to know: what if I skip the first instruction and start from the second? What if I start from the third? For each scenario, we need to count how many steps we can take before hitting a wall.

The brute force approach is actually the most straightforward here: for each possible starting index i in the string, we simulate the robot's movement from that point onwards. We keep track of the robot's current position and try to execute each instruction in sequence. If a move would take the robot outside the grid (row or column becomes negative or >= n), we stop counting. Otherwise, we update the position and increment our counter.

The key insight is that we need to:

  1. Reset the robot to its original starting position for each new starting index
  2. Map each direction character to its corresponding coordinate change: 'L' means [0, -1], 'R' means [0, 1], 'U' means [-1, 0], and 'D' means [1, 0]
  3. Before making each move, check if the new position would be valid (within bounds)

Since we need to compute this for all m starting positions and for each position we might execute up to m instructions in the worst case, the time complexity is O(m²). This is acceptable given typical constraints, and the simulation approach gives us exactly what we need without any complex preprocessing or optimization.

Solution Approach

The solution implements a straightforward simulation approach using nested loops to test each possible starting position.

Data Structure Setup: We use a dictionary mp to map each direction character to its corresponding movement vector:

mp = {"L": [0, -1], "R": [0, 1], "U": [-1, 0], "D": [1, 0]}

This makes it easy to translate instructions into coordinate changes.

Main Algorithm:

  1. Outer Loop - Iterate through each possible starting index i from 0 to m-1:

    for i in range(m):
  2. Initialize for Each Starting Position:

    • Reset the robot's position to the original startPos
    • Initialize a counter t = 0 to track valid moves
    x, y = startPos
    t = 0
  3. Inner Loop - Simulate execution from index i to the end:

    for j in range(i, m):
  4. Process Each Instruction:

    • Get the movement vector for the current instruction: a, b = mp[s[j]]
    • Check if the move would keep the robot in bounds: 0 <= x + a < n and 0 <= y + b < n
    • If valid, update position and increment counter: x, y, t = x + a, y + b, t + 1
    • If invalid, break out of the inner loop
  5. Store Result: After simulating from position i, append the count t to the answer array.

Boundary Checking: The condition 0 <= x + a < n and 0 <= y + b < n ensures both:

  • The robot doesn't go below row/column 0 (left or top boundary)
  • The robot doesn't reach or exceed row/column n (right or bottom boundary)

Time Complexity: O(m²) where m is the length of the instruction string, as we potentially examine all remaining instructions for each starting position.

Space Complexity: O(1) excluding the output array, as we only use a few variables to track position and counts.

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 small example to illustrate the solution approach.

Given:

  • Grid size: n = 3 (3×3 grid)
  • Starting position: startPos = [0, 1] (top row, middle column)
  • Instructions: s = "RRDDLU"

Grid visualization:

[0,0] [0,1] [0,2]
[1,0] [1,1] [1,2]
[2,0] [2,1] [2,2]

Direction mapping:

  • 'R' → [0, 1] (move right)
  • 'D' → [1, 0] (move down)
  • 'L' → [0, -1] (move left)
  • 'U' → [-1, 0] (move up)

Simulating each starting position:

Starting from index 0 (s = "RRDDLU"):

  • Position: [0,1], instruction 'R' → [0,2] ✓ (valid, count = 1)
  • Position: [0,2], instruction 'R' → [0,3] ✗ (out of bounds, stop)
  • Result: 1

Starting from index 1 (s = "RDDLU"):

  • Position: [0,1], instruction 'R' → [0,2] ✓ (count = 1)
  • Position: [0,2], instruction 'D' → [1,2] ✓ (count = 2)
  • Position: [1,2], instruction 'D' → [2,2] ✓ (count = 3)
  • Position: [2,2], instruction 'L' → [2,1] ✓ (count = 4)
  • Position: [2,1], instruction 'U' → [1,1] ✓ (count = 5)
  • Result: 5

Starting from index 2 (s = "DDLU"):

  • Position: [0,1], instruction 'D' → [1,1] ✓ (count = 1)
  • Position: [1,1], instruction 'D' → [2,1] ✓ (count = 2)
  • Position: [2,1], instruction 'L' → [2,0] ✓ (count = 3)
  • Position: [2,0], instruction 'U' → [1,0] ✓ (count = 4)
  • Result: 4

Starting from index 3 (s = "DLU"):

  • Position: [0,1], instruction 'D' → [1,1] ✓ (count = 1)
  • Position: [1,1], instruction 'L' → [1,0] ✓ (count = 2)
  • Position: [1,0], instruction 'U' → [0,0] ✓ (count = 3)
  • Result: 3

Starting from index 4 (s = "LU"):

  • Position: [0,1], instruction 'L' → [0,0] ✓ (count = 1)
  • Position: [0,0], instruction 'U' → [-1,0] ✗ (out of bounds, stop)
  • Result: 1

Starting from index 5 (s = "U"):

  • Position: [0,1], instruction 'U' → [-1,1] ✗ (out of bounds, stop)
  • Result: 0

Final answer: [1, 5, 4, 3, 1, 0]

The algorithm correctly simulates each starting position, tracking how many valid moves can be made before either hitting a boundary or running out of instructions.

Solution Implementation

1class Solution:
2    def executeInstructions(self, n: int, startPos: List[int], s: str) -> List[int]:
3        """
4        For each starting index in string s, count how many valid moves can be executed
5        within an n x n grid starting from startPos.
6      
7        Args:
8            n: Size of the square grid (n x n)
9            startPos: Starting position [row, col] in the grid
10            s: String of instructions where L=left, R=right, U=up, D=down
11      
12        Returns:
13            List where result[i] = number of valid moves starting from instruction i
14        """
15        result = []
16        num_instructions = len(s)
17      
18        # Direction mappings: instruction -> [row_delta, col_delta]
19        directions = {
20            "L": [0, -1],  # Move left: column decreases
21            "R": [0, 1],   # Move right: column increases
22            "U": [-1, 0],  # Move up: row decreases
23            "D": [1, 0]    # Move down: row increases
24        }
25      
26        # Try starting from each position in the instruction string
27        for start_idx in range(num_instructions):
28            current_row, current_col = startPos
29            valid_moves_count = 0
30          
31            # Execute instructions starting from start_idx
32            for instruction_idx in range(start_idx, num_instructions):
33                # Get the direction deltas for current instruction
34                row_delta, col_delta = directions[s[instruction_idx]]
35              
36                # Check if the next position would be within grid bounds
37                next_row = current_row + row_delta
38                next_col = current_col + col_delta
39              
40                if 0 <= next_row < n and 0 <= next_col < n:
41                    # Valid move: update position and increment counter
42                    current_row = next_row
43                    current_col = next_col
44                    valid_moves_count += 1
45                else:
46                    # Invalid move: stop executing further instructions
47                    break
48          
49            result.append(valid_moves_count)
50      
51        return result
52
1class Solution {
2    public int[] executeInstructions(int n, int[] startPos, String s) {
3        int instructionCount = s.length();
4        int[] result = new int[instructionCount];
5      
6        // Create a mapping of directions to their corresponding row/column changes
7        Map<Character, int[]> directionMap = new HashMap<>(4);
8        directionMap.put('L', new int[] {0, -1});  // Left: no row change, column -1
9        directionMap.put('R', new int[] {0, 1});   // Right: no row change, column +1
10        directionMap.put('U', new int[] {-1, 0});  // Up: row -1, no column change
11        directionMap.put('D', new int[] {1, 0});   // Down: row +1, no column change
12      
13        // For each starting instruction index, calculate maximum executable instructions
14        for (int startIndex = 0; startIndex < instructionCount; startIndex++) {
15            int currentRow = startPos[0];
16            int currentCol = startPos[1];
17            int executedCount = 0;
18          
19            // Try to execute instructions starting from startIndex
20            for (int currentIndex = startIndex; currentIndex < instructionCount; currentIndex++) {
21                char instruction = s.charAt(currentIndex);
22                int[] movement = directionMap.get(instruction);
23                int rowChange = movement[0];
24                int colChange = movement[1];
25              
26                // Calculate new position
27                int newRow = currentRow + rowChange;
28                int newCol = currentCol + colChange;
29              
30                // Check if new position is within grid boundaries
31                if (newRow >= 0 && newRow < n && newCol >= 0 && newCol < n) {
32                    // Valid move: update position and increment counter
33                    currentRow = newRow;
34                    currentCol = newCol;
35                    executedCount++;
36                } else {
37                    // Out of bounds: stop executing instructions
38                    break;
39                }
40            }
41          
42            // Store the count of executed instructions for this starting index
43            result[startIndex] = executedCount;
44        }
45      
46        return result;
47    }
48}
49
1class Solution {
2public:
3    vector<int> executeInstructions(int n, vector<int>& startPos, string s) {
4        int instructionCount = s.size();
5        vector<int> result(instructionCount);
6      
7        // Map each direction character to its corresponding row and column deltas
8        unordered_map<char, vector<int>> directionMap;
9        directionMap['L'] = {0, -1};  // Left: no row change, column decreases
10        directionMap['R'] = {0, 1};   // Right: no row change, column increases
11        directionMap['U'] = {-1, 0};  // Up: row decreases, no column change
12        directionMap['D'] = {1, 0};   // Down: row increases, no column change
13      
14        // For each starting instruction index, calculate maximum valid moves
15        for (int startIndex = 0; startIndex < instructionCount; ++startIndex) {
16            int currentRow = startPos[0];
17            int currentCol = startPos[1];
18            int validMoves = 0;
19          
20            // Try to execute instructions starting from startIndex
21            for (int instructionIndex = startIndex; instructionIndex < instructionCount; ++instructionIndex) {
22                // Get the direction deltas for current instruction
23                int rowDelta = directionMap[s[instructionIndex]][0];
24                int colDelta = directionMap[s[instructionIndex]][1];
25              
26                // Check if the next position would be within grid bounds
27                int nextRow = currentRow + rowDelta;
28                int nextCol = currentCol + colDelta;
29              
30                if (nextRow >= 0 && nextRow < n && nextCol >= 0 && nextCol < n) {
31                    // Valid move: update position and increment counter
32                    currentRow = nextRow;
33                    currentCol = nextCol;
34                    ++validMoves;
35                } else {
36                    // Out of bounds: stop executing instructions
37                    break;
38                }
39            }
40          
41            result[startIndex] = validMoves;
42        }
43      
44        return result;
45    }
46};
47
1/**
2 * Executes movement instructions on a grid and returns the maximum number of instructions
3 * that can be executed starting from each position without going out of bounds.
4 * 
5 * @param n - The size of the n x n grid
6 * @param startPos - The starting position [row, column] on the grid
7 * @param s - String of instructions where 'U'=up, 'D'=down, 'L'=left, 'R'=right
8 * @returns Array where ans[i] represents the maximum number of consecutive instructions
9 *          that can be executed starting from instruction i
10 */
11function executeInstructions(n: number, startPos: number[], s: string): number[] {
12    const instructionCount: number = s.length;
13    const result: number[] = new Array(instructionCount);
14  
15    // Try starting from each instruction position
16    for (let startIndex: number = 0; startIndex < instructionCount; startIndex++) {
17        // Initialize current position from the starting position
18        let currentRow: number = startPos[0];
19        let currentCol: number = startPos[1];
20        let endIndex: number;
21      
22        // Execute instructions sequentially from startIndex
23        for (endIndex = startIndex; endIndex < instructionCount; endIndex++) {
24            const instruction: string = s[endIndex];
25          
26            // Update position based on instruction
27            if (instruction === 'U') {
28                currentRow--; // Move up (decrease row)
29            } else if (instruction === 'D') {
30                currentRow++; // Move down (increase row)
31            } else if (instruction === 'L') {
32                currentCol--; // Move left (decrease column)
33            } else {
34                currentCol++; // Move right (increase column)
35            }
36          
37            // Check if the new position is out of bounds
38            if (currentRow === -1 || currentRow === n || currentCol === -1 || currentCol === n) {
39                break; // Stop execution if we go out of bounds
40            }
41        }
42      
43        // Store the count of successfully executed instructions
44        result[startIndex] = endIndex - startIndex;
45    }
46  
47    return result;
48}
49

Time and Space Complexity

Time Complexity: O(m²)

The code contains two nested loops:

  • The outer loop runs m times where m = len(s) (the length of the instruction string)
  • For each iteration of the outer loop, the inner loop can run up to m - i times in the worst case
  • In the worst case where all moves are valid, the total number of operations is: m + (m-1) + (m-2) + ... + 1 = m(m+1)/2
  • This simplifies to O(m²)

Space Complexity: O(1) excluding output, O(m) including output

  • The code uses a constant amount of extra space for variables: x, y, t, a, b, and the dictionary mp
  • The dictionary mp has a fixed size of 4 entries regardless of input size
  • The answer list ans stores m elements, but this is required for the output
  • If we exclude the space needed for the output, the space complexity is O(1)
  • If we include the output space, the space complexity is O(m)

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

Common Pitfalls

1. Modifying the Original Starting Position

A critical mistake is accidentally modifying the original startPos instead of creating a copy for each simulation. This would cause incorrect results for subsequent starting indices.

Incorrect approach:

for i in range(m):
    position = startPos  # WRONG: This creates a reference, not a copy!
    position[0] += row_delta  # This modifies the original startPos!

Correct approach:

for i in range(m):
    current_row, current_col = startPos  # Creates new variables with values
    # OR
    position = startPos.copy()  # Creates an actual copy of the list

2. Off-by-One Errors in Boundary Checking

Confusing inclusive vs exclusive bounds is a common mistake. The grid has valid indices from 0 to n-1, not 0 to n.

Incorrect boundary check:

if 0 <= next_row <= n and 0 <= next_col <= n:  # WRONG: allows position n

Correct boundary check:

if 0 <= next_row < n and 0 <= next_col < n:  # Correct: excludes position n

3. Updating Position Before Validation

Moving the robot before checking if the move is valid leads to incorrect positions and counts.

Incorrect order:

for j in range(i, m):
    row_delta, col_delta = directions[s[j]]
    current_row += row_delta  # WRONG: Updates before checking validity
    current_col += col_delta
    if 0 <= current_row < n and 0 <= current_col < n:
        valid_moves_count += 1
    else:
        break  # Position is already corrupted!

Correct order:

for j in range(i, m):
    row_delta, col_delta = directions[s[j]]
    next_row = current_row + row_delta  # Calculate without updating
    next_col = current_col + col_delta
    if 0 <= next_row < n and 0 <= next_col < n:
        current_row = next_row  # Update only after validation
        current_col = next_col
        valid_moves_count += 1
    else:
        break

4. Incorrect Direction Mappings

Mixing up the coordinate system (row, column) with direction meanings can cause the robot to move incorrectly.

Common confusion:

  • Remember that row index increases downward (U decreases row, D increases row)
  • Column index increases rightward (L decreases column, R increases column)

Incorrect mapping:

directions = {
    "U": [1, 0],   # WRONG: Up should decrease row, not increase
    "D": [-1, 0],  # WRONG: Down should increase row, not decrease
}

5. Not Breaking the Loop After Invalid Move

Forgetting to break when encountering an invalid move would skip that instruction but continue with others, which violates the problem requirements.

Incorrect implementation:

for j in range(i, m):
    if valid_move:
        # execute move
        valid_moves_count += 1
    # WRONG: Missing break, continues to next instruction even after invalid move

Correct implementation:

for j in range(i, m):
    if valid_move:
        # execute move
        valid_moves_count += 1
    else:
        break  # Stop immediately upon encountering invalid move
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following uses divide and conquer strategy?


Recommended Readings

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

Load More