Facebook Pixel

3522. Calculate Score After Performing Instructions

MediumArrayHash TableStringSimulation
Leetcode Link

Problem Description

You have two arrays of the same size n: instructions and values. You need to simulate a process that follows specific rules to calculate a final score.

Starting conditions:

  • Begin at index i = 0
  • Initial score is 0

Process rules:

When at index i, check instructions[i]:

  • If instructions[i] is "add":

    • Add values[i] to your current score
    • Move to the next index (i + 1)
  • If instructions[i] is "jump":

    • Jump to index i + values[i] (don't change the score)

Termination conditions:

The process stops when either:

  1. You go out of bounds (index becomes less than 0 or greater than or equal to n)
  2. You reach an instruction that you've already executed before (you don't execute it again)

Goal: Return the final score when the process ends.

Example walkthrough:

If instructions = ["add", "jump", "add"] and values = [2, 1, 3]:

  • Start at index 0: instruction is "add", so add 2 to score (score = 2), move to index 1
  • At index 1: instruction is "jump", so jump to index 1 + 1 = 2
  • At index 2: instruction is "add", so add 3 to score (score = 5), move to index 3
  • Index 3 is out of bounds, so the process ends
  • Return score = 5

The solution uses a visited array to track which instructions have been executed, ensuring we stop if we encounter a previously visited instruction.

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

Intuition

The problem asks us to follow a sequence of instructions that either modify our score or change our position in the instruction array. This is essentially a simulation problem where we need to trace through the execution path.

The key insight is recognizing that we need to track which instructions we've already visited. Why? Because the problem states that if we try to revisit an instruction, the process terminates immediately without executing that instruction again. This prevents us from getting stuck in infinite loops.

Consider what could happen without tracking visits: if we have instructions = ["jump", "jump"] and values = [1, -1], we would jump from index 0 to index 1, then from index 1 back to index 0, creating an infinite loop. The visited tracking mechanism breaks this cycle.

The natural approach is to:

  1. Keep a boolean array vis to mark which instructions we've executed
  2. Follow the instructions sequentially, updating our position based on the instruction type
  3. Stop when we either go out of bounds or encounter a previously visited instruction

The simulation is straightforward because we're simply following the rules as stated:

  • For "add" instructions: update score and move forward by 1
  • For "jump" instructions: move by the specified offset without changing score

Since we can only visit each instruction at most once (due to the termination condition), the time complexity is O(n) where n is the length of the arrays. Each instruction is processed at most once, making this an efficient linear solution.

Solution Approach

The implementation follows a direct simulation approach using a visited tracking mechanism.

Data Structures Used:

  • A boolean array vis of size n to track which instructions have been executed
  • Variables ans to store the accumulated score and i to track the current instruction index

Algorithm Steps:

  1. Initialize the tracking structures:

    • Create a boolean array vis = [False] * n to mark all instructions as unvisited
    • Set ans = 0 for the score and i = 0 for the starting position
  2. Main simulation loop:

    • Continue while two conditions are met:
      • Position is within bounds: 0 <= i < n
      • Current instruction hasn't been visited: not vis[i]
  3. Inside each iteration:

    • Mark current instruction as visited: vis[i] = True
    • Check the instruction type by examining the first character:
      • If instructions[i][0] == "a" (checking if it starts with 'a' for "add"):
        • Add the value to score: ans += values[i]
        • Move to next instruction: i += 1
      • Otherwise (it's a "jump" instruction):
        • Jump to the new position: i = i + values[i]
  4. Termination:

    • The loop naturally exits when either:
      • We go out of bounds (i < 0 or i >= n)
      • We encounter a previously visited instruction (vis[i] is True)
    • Return the final score ans

Key Implementation Details:

The solution cleverly uses instructions[i][0] == "a" to distinguish between "add" and "jump" instructions. This is more efficient than comparing the entire string.

The visited array prevents infinite loops and ensures linear time complexity. Without it, we could potentially cycle through the same instructions indefinitely.

Time Complexity: O(n) - Each instruction can be visited at most once Space Complexity: O(n) - For the visited array

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

Input: instructions = ["add", "jump", "add", "jump", "add"] and values = [3, 2, 1, -4, 5]

Step-by-step execution:

Initial state:

  • vis = [False, False, False, False, False] (all unvisited)
  • ans = 0 (score)
  • i = 0 (current position)

Iteration 1:

  • Position i = 0, check conditions: 0 <= 0 < 5 ✓ and vis[0] = False
  • Mark visited: vis[0] = Truevis = [True, False, False, False, False]
  • Instruction is "add" (first char is 'a')
  • Add to score: ans = 0 + 3 = 3
  • Move forward: i = 0 + 1 = 1

Iteration 2:

  • Position i = 1, check conditions: 0 <= 1 < 5 ✓ and vis[1] = False
  • Mark visited: vis[1] = Truevis = [True, True, False, False, False]
  • Instruction is "jump" (first char is not 'a')
  • Jump: i = 1 + 2 = 3 (no score change)

Iteration 3:

  • Position i = 3, check conditions: 0 <= 3 < 5 ✓ and vis[3] = False
  • Mark visited: vis[3] = Truevis = [True, True, False, True, False]
  • Instruction is "jump" (first char is not 'a')
  • Jump: i = 3 + (-4) = -1 (no score change)

Termination:

  • Position i = -1, check conditions: 0 <= -1 < 5 ✗ (out of bounds)
  • Loop exits

Final result: Return ans = 3

This example demonstrates:

  • How the visited array tracks executed instructions
  • The difference between "add" (updates score and moves by 1) and "jump" (changes position by value)
  • Termination when going out of bounds
  • Note that indices 2 and 4 were never visited because our path jumped over them

Solution Implementation

1class Solution:
2    def calculateScore(self, instructions: List[str], values: List[int]) -> int:
3        """
4        Calculate score by following instructions and accumulating values.
5      
6        Args:
7            instructions: List of instruction strings starting with 'a' or other characters
8            values: List of integer values corresponding to each instruction
9      
10        Returns:
11            Total accumulated score based on instructions
12        """
13        n = len(values)
14        visited = [False] * n  # Track visited indices to avoid infinite loops
15        total_score = 0
16        current_index = 0
17      
18        # Process instructions while within bounds and not revisiting indices
19        while 0 <= current_index < n and not visited[current_index]:
20            # Mark current position as visited
21            visited[current_index] = True
22          
23            # Check instruction type
24            if instructions[current_index][0] == "a":
25                # If instruction starts with 'a', add value to score and move forward
26                total_score += values[current_index]
27                current_index += 1
28            else:
29                # Otherwise, jump by the value amount
30                current_index = current_index + values[current_index]
31      
32        return total_score
33
1class Solution {
2    /**
3     * Calculates the total score by traversing through instructions array
4     * based on the given rules.
5     * 
6     * @param instructions Array of instruction strings
7     * @param values Array of integer values corresponding to each instruction
8     * @return The total accumulated score
9     */
10    public long calculateScore(String[] instructions, int[] values) {
11        int arrayLength = values.length;
12      
13        // Track visited indices to avoid infinite loops
14        boolean[] visited = new boolean[arrayLength];
15      
16        // Initialize total score
17        long totalScore = 0;
18      
19        // Start from index 0
20        int currentIndex = 0;
21
22        // Continue traversing while:
23        // 1. Current index is within bounds (not negative and less than array length)
24        // 2. Current index hasn't been visited before (to prevent cycles)
25        while (currentIndex >= 0 && currentIndex < arrayLength && !visited[currentIndex]) {
26            // Mark current index as visited
27            visited[currentIndex] = true;
28          
29            // Check the first character of the instruction
30            if (instructions[currentIndex].charAt(0) == 'a') {
31                // If instruction starts with 'a', add value to score and move to next index
32                totalScore += values[currentIndex];
33                currentIndex += 1;
34            } else {
35                // Otherwise, jump by the value at current index
36                currentIndex = currentIndex + values[currentIndex];
37            }
38        }
39
40        return totalScore;
41    }
42}
43
1class Solution {
2public:
3    long long calculateScore(vector<string>& instructions, vector<int>& values) {
4        int n = values.size();
5      
6        // Track visited indices to detect cycles
7        vector<bool> visited(n, false);
8      
9        // Initialize score accumulator
10        long long totalScore = 0;
11      
12        // Start from index 0
13        int currentIndex = 0;
14
15        // Continue traversing while:
16        // 1. Current index is within bounds (0 to n-1)
17        // 2. Current index hasn't been visited (no cycle detected)
18        while (currentIndex >= 0 && currentIndex < n && !visited[currentIndex]) {
19            // Mark current index as visited
20            visited[currentIndex] = true;
21          
22            // Check instruction type
23            if (instructions[currentIndex][0] == 'a') {
24                // "add" instruction: add value to score and move to next index
25                totalScore += values[currentIndex];
26                currentIndex += 1;
27            } else {
28                // "jump" instruction: jump by the value amount
29                currentIndex += values[currentIndex];
30            }
31        }
32
33        return totalScore;
34    }
35};
36
1/**
2 * Calculates the score by traversing through instructions based on their type.
3 * @param instructions - Array of instruction strings where each starts with 'a' or other character
4 * @param values - Array of numerical values corresponding to each instruction
5 * @returns The calculated score after processing all reachable instructions
6 */
7function calculateScore(instructions: string[], values: number[]): number {
8    // Get the length of the arrays
9    const arrayLength: number = values.length;
10  
11    // Track visited indices to avoid infinite loops
12    const visited: boolean[] = Array(arrayLength).fill(false);
13  
14    // Initialize the accumulated score
15    let totalScore: number = 0;
16  
17    // Current index pointer for traversing instructions
18    let currentIndex: number = 0;
19
20    // Continue processing while index is valid and not previously visited
21    while (currentIndex >= 0 && currentIndex < arrayLength && !visited[currentIndex]) {
22        // Mark current index as visited
23        visited[currentIndex] = true;
24      
25        // Check instruction type
26        if (instructions[currentIndex][0] === 'a') {
27            // 'a' type: add value to score and move to next instruction
28            totalScore += values[currentIndex];
29            currentIndex += 1;
30        } else {
31            // Other type: jump by the value amount
32            currentIndex += values[currentIndex];
33        }
34    }
35
36    return totalScore;
37}
38

Time and Space Complexity

Time Complexity: O(n)

The algorithm uses a while loop that traverses through the array based on instructions. Each element in the array is visited at most once, as tracked by the vis (visited) array. Once an element is visited (vis[i] = True), it won't be processed again. The loop continues while the index i is within bounds (0 <= i < n) and the current element hasn't been visited (not vis[i]). Since each element can only be visited once, the maximum number of iterations is n, where n is the length of the arrays.

Space Complexity: O(n)

The algorithm uses a boolean array vis of size n to track which elements have been visited. This auxiliary array requires O(n) space. The remaining variables (ans, i, n) use constant space O(1). Therefore, the overall space complexity is O(n), where n is the length of the input array values.

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

Common Pitfalls

1. Incorrect Jump Calculation

A frequent mistake is misunderstanding how the jump works. The jump destination is i + values[i], not just values[i].

Wrong Implementation:

if instructions[current_index][0] != "a":
    current_index = values[current_index]  # WRONG: This jumps to absolute position

Correct Implementation:

if instructions[current_index][0] != "a":
    current_index = current_index + values[current_index]  # Correct: Relative jump

2. Forgetting to Mark Visited Before Processing

Marking the instruction as visited must happen before processing it, not after. Otherwise, you might process the same instruction twice in edge cases.

Wrong Implementation:

while 0 <= current_index < n and not visited[current_index]:
    if instructions[current_index][0] == "a":
        total_score += values[current_index]
        current_index += 1
    else:
        current_index = current_index + values[current_index]
    visited[current_index] = True  # WRONG: Might be out of bounds here

Correct Implementation:

while 0 <= current_index < n and not visited[current_index]:
    visited[current_index] = True  # Mark as visited first
    # Then process the instruction

3. Handling Negative Jump Values

The problem allows negative values in the values array, which means jumps can go backward. Not accounting for this can lead to incorrect assumptions about the flow.

Example Case:

instructions = ["jump", "add", "add"]
values = [-1, 5, 3]
# Starting at index 0, jumping by -1 would take us to index -1 (out of bounds)

4. String Comparison Efficiency

Using full string comparison can be inefficient and error-prone with typos.

Less Efficient:

if instructions[current_index] == "add":  # Full string comparison

More Efficient and Safer:

if instructions[current_index][0] == "a":  # Just check first character

5. Not Initializing Visited Array Properly

Ensure the visited array matches the size of the input arrays exactly.

Wrong:

visited = [False] * (n + 1)  # Wrong size - could mask bugs

Correct:

visited = [False] * n  # Exact size matching input arrays
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".

What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?


Recommended Readings

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

Load More