Facebook Pixel

1165. Single-Row Keyboard 🔒

EasyHash TableString
Leetcode Link

Problem Description

You have a special keyboard where all keys are arranged in a single row. The keyboard layout is given as a string keyboard of length 26, where each character represents a key and its position (index 0 to 25) indicates where it is located on the keyboard.

Your finger starts at position 0 on the keyboard. To type a character, you need to move your finger from its current position to the position of the desired character. The time required to move from position i to position j is calculated as the absolute difference |i - j|.

Given a string word that you want to type, calculate the total time needed to type the entire word using one finger.

For example, if the keyboard is "abcdefghijklmnopqrstuvwxyz" and you want to type "cba":

  • Start at position 0
  • Move to 'c' at position 2: time = |2 - 0| = 2
  • Move to 'b' at position 1: time = |1 - 2| = 1
  • Move to 'a' at position 0: time = |0 - 1| = 1
  • Total time = 2 + 1 + 1 = 4

The solution uses a hash table to map each character to its position on the keyboard. Then it iterates through each character in word, calculating the distance from the current finger position to the target character's position, accumulating the total time, and updating the finger position after each character is typed.

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

Intuition

The key insight is that we need to track the movement of our finger across the keyboard as we type each character. Since the keyboard is a one-dimensional row, the distance between any two positions is simply the absolute difference between their indices.

To efficiently find where each character is located on the keyboard, we need a way to quickly look up the position of any character. Instead of searching through the keyboard string every time we need to type a character, we can preprocess the keyboard layout by creating a mapping from each character to its position. This gives us O(1) lookup time for each character.

Once we have this mapping, the problem becomes straightforward: we simulate the typing process. We keep track of where our finger currently is (starting at position 0), and for each character we want to type:

  1. Look up where that character is on the keyboard
  2. Calculate how far we need to move (absolute difference between current and target positions)
  3. Add this distance to our total time
  4. Update our finger's position to the new location

The total time is just the sum of all these individual movements. This approach naturally handles the sequential nature of typing - we can't skip ahead or type multiple characters simultaneously, so we must account for each movement from one character to the next.

Solution Approach

We can implement this solution using a hash table to store the position of each character on the keyboard.

First, we create a dictionary pos where each key is a character from the keyboard string and its value is the character's index position. This is done with a dictionary comprehension: pos = {c: i for i, c in enumerate(keyboard)}. This preprocessing step allows us to look up any character's position in O(1) time.

Next, we initialize two variables:

  • ans to accumulate the total time (starting at 0)
  • i to track the current finger position (starting at 0)

Then we iterate through each character c in the word we want to type:

  1. Look up the target position using pos[c]
  2. Calculate the distance moved as abs(pos[c] - i) and add it to ans
  3. Update the current finger position: i = pos[c]

After processing all characters in the word, ans contains the total time needed to type the entire word.

The time complexity is O(n + m) where n is the length of the keyboard (always 26) and m is the length of the word. The space complexity is O(1) since the hash table always stores exactly 26 character-position pairs.

This approach efficiently simulates the typing process by tracking finger movement across the keyboard and accumulating the distances traveled between consecutive characters.

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

Given:

  • keyboard = "pqrstuvwxyzabcdefghijklmno"
  • word = "cat"

Step 1: Build the position mapping

First, we create a hash table to map each character to its position on the keyboard:

pos = {
  'p': 0, 'q': 1, 'r': 2, 's': 3, 't': 4,
  'u': 5, 'v': 6, 'w': 7, 'x': 8, 'y': 9,
  'z': 10, 'a': 11, 'b': 12, 'c': 13, 'd': 14,
  'e': 15, 'f': 16, 'g': 17, 'h': 18, 'i': 19,
  'j': 20, 'k': 21, 'l': 22, 'm': 23, 'n': 24, 'o': 25
}

Step 2: Initialize variables

  • ans = 0 (total time accumulated)
  • i = 0 (current finger position, starting at index 0)

Step 3: Process each character in "cat"

Character 'c':

  • Look up position: pos['c'] = 13
  • Calculate distance: |13 - 0| = 13
  • Update total time: ans = 0 + 13 = 13
  • Update finger position: i = 13

Character 'a':

  • Look up position: pos['a'] = 11
  • Calculate distance: |11 - 13| = 2
  • Update total time: ans = 13 + 2 = 15
  • Update finger position: i = 11

Character 't':

  • Look up position: pos['t'] = 4
  • Calculate distance: |4 - 11| = 7
  • Update total time: ans = 15 + 7 = 22
  • Update finger position: i = 4

Step 4: Return the result

The total time needed to type "cat" is 22.

This example demonstrates how the algorithm tracks the finger's movement across the keyboard, calculating the distance for each character transition and accumulating the total time required.

Solution Implementation

1class Solution:
2    def calculateTime(self, keyboard: str, word: str) -> int:
3        # Create a dictionary mapping each character to its position on the keyboard
4        char_to_position = {char: index for index, char in enumerate(keyboard)}
5      
6        # Initialize total time and current finger position (starts at index 0)
7        total_time = 0
8        current_position = 0
9      
10        # Process each character in the word
11        for char in word:
12            # Calculate time as distance from current position to target character position
13            total_time += abs(char_to_position[char] - current_position)
14          
15            # Update current finger position to where we just typed
16            current_position = char_to_position[char]
17      
18        return total_time
19
1class Solution {
2    public int calculateTime(String keyboard, String word) {
3        // Create an array to store the position of each character on the keyboard
4        // Index represents the character (0 for 'a', 1 for 'b', etc.)
5        // Value represents the position on the keyboard
6        int[] charPositions = new int[26];
7      
8        // Map each character to its position on the keyboard
9        for (int i = 0; i < 26; i++) {
10            char currentChar = keyboard.charAt(i);
11            int charIndex = currentChar - 'a';  // Convert character to index (0-25)
12            charPositions[charIndex] = i;
13        }
14      
15        // Initialize total time and current finger position
16        int totalTime = 0;
17        int currentPosition = 0;  // Finger starts at position 0
18      
19        // Calculate time for typing each character in the word
20        for (int i = 0; i < word.length(); i++) {
21            // Get the target position for the current character
22            char currentChar = word.charAt(i);
23            int charIndex = currentChar - 'a';
24            int targetPosition = charPositions[charIndex];
25          
26            // Add the distance from current position to target position
27            totalTime += Math.abs(currentPosition - targetPosition);
28          
29            // Update current finger position
30            currentPosition = targetPosition;
31        }
32      
33        return totalTime;
34    }
35}
36
1class Solution {
2public:
3    int calculateTime(string keyboard, string word) {
4        // Create an array to store the position of each character on the keyboard
5        // charPosition[i] represents the index position of character ('a' + i) on the keyboard
6        int charPosition[26];
7      
8        // Build the position mapping for each character in the keyboard
9        for (int index = 0; index < 26; ++index) {
10            charPosition[keyboard[index] - 'a'] = index;
11        }
12      
13        // Initialize total time and current finger position
14        int totalTime = 0;
15        int currentPosition = 0;  // Finger starts at position 0
16      
17        // Calculate time for typing each character in the word
18        for (char& character : word) {
19            // Get the target position for the current character
20            int targetPosition = charPosition[character - 'a'];
21          
22            // Add the time (distance) to move from current position to target position
23            totalTime += abs(currentPosition - targetPosition);
24          
25            // Update current finger position
26            currentPosition = targetPosition;
27        }
28      
29        return totalTime;
30    }
31};
32
1/**
2 * Calculates the total time needed to type a word on a custom keyboard layout
3 * @param keyboard - A string of 26 lowercase letters representing the keyboard layout
4 * @param word - The word to be typed
5 * @returns The total time (distance) needed to type the word
6 */
7function calculateTime(keyboard: string, word: string): number {
8    // Create an array to store the position of each letter on the keyboard
9    // Index represents the letter (a=0, b=1, ..., z=25), value represents its position on keyboard
10    const letterPositions: number[] = Array(26).fill(0);
11  
12    // Map each letter to its position on the keyboard
13    for (let i = 0; i < 26; i++) {
14        // Get the letter's ASCII value minus 97 (ASCII of 'a') to get index 0-25
15        const letterIndex = keyboard.charCodeAt(i) - 97;
16        letterPositions[letterIndex] = i;
17    }
18  
19    // Initialize total time and current finger position (starts at position 0)
20    let totalTime = 0;
21    let currentPosition = 0;
22  
23    // Calculate time for each character in the word
24    for (const character of word) {
25        // Get the target position of the current character on the keyboard
26        const targetPosition = letterPositions[character.charCodeAt(0) - 97];
27      
28        // Add the distance from current position to target position
29        totalTime += Math.abs(currentPosition - targetPosition);
30      
31        // Update current position to the target position
32        currentPosition = targetPosition;
33    }
34  
35    return totalTime;
36}
37

Time and Space Complexity

The time complexity is O(n + k) where n is the length of the string word and k is the length of the keyboard string (which is 26 for all lowercase letters). The O(k) comes from creating the position dictionary by iterating through the keyboard string, and O(n) comes from iterating through each character in the word. Since k is constant (26), this simplifies to O(n).

The space complexity is O(k) or O(26) = O(1) where k represents the size of the character set. The position dictionary pos stores at most 26 key-value pairs (one for each letter in the keyboard). Since this is a constant amount of space regardless of input size, it can also be expressed as O(C) where C = 26 is the size of the character set.

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

Common Pitfalls

1. Forgetting to Update the Current Position

A frequent mistake is calculating the distance correctly but forgetting to update the finger's current position after typing each character. This leads to incorrect distance calculations for subsequent characters.

Incorrect Implementation:

def calculateTime(self, keyboard: str, word: str) -> int:
    char_to_position = {char: index for index, char in enumerate(keyboard)}
    total_time = 0
    current_position = 0
  
    for char in word:
        total_time += abs(char_to_position[char] - current_position)
        # MISTAKE: Forgot to update current_position!
  
    return total_time

This code would always calculate distances from position 0, giving wrong results for any word with more than one character.

Correct Solution: Always update the current position after calculating the distance:

for char in word:
    total_time += abs(char_to_position[char] - current_position)
    current_position = char_to_position[char]  # Don't forget this line!

2. Starting from the Wrong Initial Position

Another pitfall is misunderstanding the initial finger position. The problem states the finger starts at position 0 (the first character of the keyboard), not at the position of the first character in the word.

Incorrect Implementation:

def calculateTime(self, keyboard: str, word: str) -> int:
    char_to_position = {char: index for index, char in enumerate(keyboard)}
  
    # MISTAKE: Starting at the first character of the word
    current_position = char_to_position[word[0]]
    total_time = current_position  # Distance from 0 to first character
  
    for i in range(1, len(word)):
        total_time += abs(char_to_position[word[i]] - current_position)
        current_position = char_to_position[word[i]]
  
    return total_time

While this might seem logical, it adds unnecessary complexity and can lead to index errors if the word is empty.

Correct Solution: Always start from position 0 and let the loop handle all characters uniformly:

current_position = 0  # Always start at position 0
for char in word:    # Process all characters the same way
    total_time += abs(char_to_position[char] - current_position)
    current_position = char_to_position[char]

3. Not Handling Edge Cases

Failing to consider edge cases like an empty word string can cause errors.

Potential Issue: If word is empty, the code should return 0 (no time needed to type nothing). The provided solution handles this correctly because the loop simply doesn't execute, and total_time remains 0.

Best Practice: While the current solution handles empty strings naturally, you could add explicit validation if needed:

if not word:
    return 0

These pitfalls highlight the importance of careful state management and understanding the problem's initial conditions when implementing simulation-based algorithms.

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

Which type of traversal does breadth first search do?


Recommended Readings

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

Load More