Facebook Pixel

1844. Replace All Digits with Characters

EasyString
Leetcode Link

Problem Description

You are given a string s where:

  • Characters at even indices (0, 2, 4, ...) are lowercase English letters
  • Characters at odd indices (1, 3, 5, ...) are digits

Your task is to transform the string by replacing each digit with a new character. The replacement follows a specific rule based on a shift operation.

The shift(c, x) operation takes:

  • c: a character (letter)
  • x: a digit (number)

It returns the character that is x positions after c in the alphabet. For example:

  • shift('a', 5) returns 'f' (because 'f' is 5 positions after 'a')
  • shift('x', 0) returns 'x' (because 0 positions after 'x' is still 'x')

For each odd index i in the string, you need to:

  1. Take the character at position i-1 (which will be a letter)
  2. Take the digit at position i
  3. Replace the digit at position i with the result of shift(s[i-1], s[i])

The problem guarantees that the shift operation will never produce a character beyond 'z'.

Example walkthrough: If s = "a1c1e1":

  • Index 1: Replace '1' with shift('a', 1) = 'b'
  • Index 3: Replace '1' with shift('c', 1) = 'd'
  • Index 5: Replace '1' with shift('e', 1) = 'f'
  • Result: "abcdef"

The solution converts the string to a list for easy modification, iterates through odd indices, applies the shift operation by using ASCII values (ord and chr functions), and joins the list back into a string.

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

Intuition

The problem is straightforward - we need to process the string and replace digits at odd positions. The key insight is recognizing that we only need to modify characters at odd indices, while characters at even indices remain unchanged.

Since we need to replace each digit with a character that's a certain number of positions after the previous character, we can think of this as a character arithmetic problem. In programming, characters are represented by ASCII values, which are numbers. For example, 'a' has ASCII value 97, 'b' has value 98, and so on.

To shift a character by x positions, we can:

  1. Convert the character to its ASCII value using ord()
  2. Add the digit value to it
  3. Convert the result back to a character using chr()

For instance, to get the character 3 positions after 'a':

  • ord('a') gives us 97
  • Add 3 to get 100
  • chr(100) gives us 'd'

The natural approach is to iterate through the string, but only process odd indices (1, 3, 5, ...). For each odd index i, we look at the character at i-1 (which is guaranteed to be a letter) and the digit at position i, then perform the shift operation.

Since strings in Python are immutable (cannot be changed directly), we convert the string to a list first, make our modifications, and then join it back into a string. This allows us to modify individual characters efficiently.

The iteration pattern range(1, len(s), 2) elegantly gives us all odd indices starting from 1, stepping by 2 each time, which is exactly what we need to process only the positions containing digits.

Solution Approach

The solution uses a simulation approach to process the string character by character. Here's the step-by-step implementation:

Step 1: Convert string to a mutable list

s = list(s)

Since Python strings are immutable, we convert the string to a list to allow in-place modifications. This gives us O(1) access to modify individual characters.

Step 2: Iterate through odd indices

for i in range(1, len(s), 2):

We start from index 1 (the first odd index) and step by 2 to visit only odd indices (1, 3, 5, ...). This ensures we only process positions that contain digits.

Step 3: Apply the shift operation

s[i] = chr(ord(s[i - 1]) + int(s[i]))

For each odd index i:

  • s[i - 1] gets the character at the previous (even) index, which is a letter
  • ord(s[i - 1]) converts this letter to its ASCII value
  • int(s[i]) converts the digit character at position i to its numeric value
  • We add these two values together
  • chr() converts the resulting ASCII value back to a character
  • The result replaces the digit at position i

Step 4: Join and return the result

return ''.join(s)

After all replacements are complete, we join the list back into a string and return it.

Example Trace: For s = "a1c1e1":

  • Initial list: ['a', '1', 'c', '1', 'e', '1']
  • i = 1: s[1] = chr(ord('a') + 1) = chr(97 + 1) = chr(98) = 'b'
  • i = 3: s[3] = chr(ord('c') + 1) = chr(99 + 1) = chr(100) = 'd'
  • i = 5: s[5] = chr(ord('e') + 1) = chr(101 + 1) = chr(102) = 'f'
  • Final result: "abcdef"

Time Complexity: O(n) where n is the length of the string, as we iterate through approximately n/2 characters.

Space Complexity: O(n) for the list conversion, though this could be considered O(1) extra space if we don't count the output string construction.

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 the solution with the example s = "m2u4y0":

Initial Setup:

  • Convert string to list: ['m', '2', 'u', '4', 'y', '0']
  • We'll process indices 1, 3, and 5 (the odd positions containing digits)

Processing Index 1:

  • Current digit: '2' at index 1
  • Previous letter: 'm' at index 0
  • Apply shift operation: shift('m', 2)
    • ASCII value of 'm' = 109
    • Add digit value 2: 109 + 2 = 111
    • Convert back to character: chr(111) = 'o'
  • Replace '2' with 'o': ['m', 'o', 'u', '4', 'y', '0']

Processing Index 3:

  • Current digit: '4' at index 3
  • Previous letter: 'u' at index 2
  • Apply shift operation: shift('u', 4)
    • ASCII value of 'u' = 117
    • Add digit value 4: 117 + 4 = 121
    • Convert back to character: chr(121) = 'y'
  • Replace '4' with 'y': ['m', 'o', 'u', 'y', 'y', '0']

Processing Index 5:

  • Current digit: '0' at index 5
  • Previous letter: 'y' at index 4
  • Apply shift operation: shift('y', 0)
    • ASCII value of 'y' = 121
    • Add digit value 0: 121 + 0 = 121
    • Convert back to character: chr(121) = 'y'
  • Replace '0' with 'y': ['m', 'o', 'u', 'y', 'y', 'y']

Final Result:

  • Join the list back to string: "mouyy"

The key insight is that we only modify odd-indexed positions, replacing each digit with a character that's shifted from the preceding letter by the digit's value.

Solution Implementation

1class Solution:
2    def replaceDigits(self, s: str) -> str:
3        """
4        Replace every digit at odd indices with the character obtained by
5        shifting the previous character by the digit's value.
6      
7        Args:
8            s: Input string containing lowercase letters and digits
9          
10        Returns:
11            Modified string with digits replaced by shifted characters
12        """
13        # Convert string to list for in-place modification
14        char_list = list(s)
15      
16        # Iterate through odd indices (1, 3, 5, ...)
17        for i in range(1, len(char_list), 2):
18            # Get the previous character (at even index)
19            prev_char = char_list[i - 1]
20          
21            # Get the digit value at current position
22            shift_value = int(char_list[i])
23          
24            # Calculate new character by shifting previous character
25            # ord() gets ASCII value, add shift, chr() converts back to character
26            new_char = chr(ord(prev_char) + shift_value)
27          
28            # Replace digit with the new character
29            char_list[i] = new_char
30      
31        # Convert list back to string and return
32        return ''.join(char_list)
33
1class Solution {
2    /**
3     * Replaces digits at odd indices with the character that is 
4     * the digit's value positions after the preceding character.
5     * 
6     * @param s the input string containing alternating letters and digits
7     * @return the string with digits replaced by shifted characters
8     */
9    public String replaceDigits(String s) {
10        // Convert string to character array for in-place modification
11        char[] charArray = s.toCharArray();
12      
13        // Iterate through odd indices (1, 3, 5, ...) where digits are located
14        for (int index = 1; index < charArray.length; index += 2) {
15            // Get the character at the previous position (even index)
16            char previousChar = charArray[index - 1];
17          
18            // Convert current digit character to its numeric value
19            int shiftAmount = charArray[index] - '0';
20          
21            // Replace digit with the character shifted from the previous character
22            charArray[index] = (char) (previousChar + shiftAmount);
23        }
24      
25        // Convert the modified character array back to string and return
26        return String.valueOf(charArray);
27    }
28}
29
1class Solution {
2public:
3    string replaceDigits(string s) {
4        int stringLength = s.size();
5      
6        // Iterate through odd indices (1, 3, 5, ...)
7        // These positions contain digits that need to be replaced
8        for (int i = 1; i < stringLength; i += 2) {
9            // Get the character at the previous position (even index)
10            char previousChar = s[i - 1];
11          
12            // Convert the digit character at current position to its numeric value
13            int shiftAmount = s[i] - '0';
14          
15            // Apply the shift operation: 
16            // Replace digit with the character that is 'shiftAmount' positions 
17            // after the previous character in the alphabet
18            s[i] = previousChar + shiftAmount;
19        }
20      
21        return s;
22    }
23};
24
1/**
2 * Replaces every digit in the string with a character formed by shifting
3 * the previous character by the digit's value in the alphabet.
4 * Characters at even indices remain unchanged, while characters at odd indices
5 * (which should be digits) are replaced with the result of shifting the previous character.
6 * 
7 * @param s - The input string containing lowercase letters and digits
8 * @returns The transformed string with digits replaced
9 */
10function replaceDigits(s: string): string {
11    // Get the length of the input string
12    const stringLength: number = s.length;
13  
14    // Convert string to array for easier character manipulation
15    const resultArray: string[] = [...s];
16  
17    // Iterate through odd indices (where digits should be located)
18    for (let index = 1; index < stringLength; index += 2) {
19        // Get the previous character's ASCII code
20        const previousCharCode: number = resultArray[index - 1].charCodeAt(0);
21      
22        // Convert current digit character to number
23        const shiftAmount: number = Number(resultArray[index]);
24      
25        // Calculate new character by shifting previous character by digit amount
26        const newCharCode: number = previousCharCode + shiftAmount;
27      
28        // Replace digit with the new character
29        resultArray[index] = String.fromCharCode(newCharCode);
30    }
31  
32    // Join the array back into a string and return
33    return resultArray.join('');
34}
35

Time and Space Complexity

Time Complexity: O(n), where n is the length of the string s. The algorithm iterates through the string once with a for loop that visits approximately n/2 elements (every odd index), and each operation inside the loop (character conversion, addition, and assignment) takes O(1) time. Therefore, the overall time complexity is O(n).

Space Complexity: O(n) for the total space used, but if we ignore the space consumption of the answer (as mentioned in the reference), the space complexity is O(1). The conversion of the string to a list creates a new list of size n, which is necessary for the output. However, aside from this required output space, no additional data structures that grow with input size are used - only constant extra variables are needed for the loop and character operations.

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

Common Pitfalls

1. Attempting Direct String Modification

One of the most common mistakes is trying to modify the string directly without converting it to a list first:

# WRONG - This will raise TypeError
def replaceDigits(self, s: str) -> str:
    for i in range(1, len(s), 2):
        s[i] = chr(ord(s[i - 1]) + int(s[i]))  # Error: strings are immutable
    return s

Solution: Always convert the string to a list first for modification, then join it back.

2. Incorrect Index Range or Step

Developers might accidentally iterate through all indices or use the wrong starting point:

# WRONG - Processes even indices instead of odd
for i in range(0, len(s), 2):  # Starts at 0, not 1
    s[i] = chr(ord(s[i - 1]) + int(s[i]))  # s[i-1] would be out of bounds when i=0

# WRONG - Processes all indices
for i in range(len(s)):  # Should only process odd indices
    if i % 2 == 1:  # Extra check needed, less efficient
        s[i] = chr(ord(s[i - 1]) + int(s[i]))

Solution: Use range(1, len(s), 2) to directly iterate through odd indices only.

3. Forgetting Type Conversions

Missing the conversion from string digit to integer or ASCII operations:

# WRONG - Concatenating character with string digit
s[i] = s[i - 1] + s[i]  # Results in string concatenation, not shifting

# WRONG - Adding character directly to digit
s[i] = chr(s[i - 1] + int(s[i]))  # Missing ord() conversion

Solution: Remember the conversion chain: character → ord() → ASCII value → add shift → chr() → character

4. Out of Bounds ASCII Values

While the problem guarantees no overflow beyond 'z', in practice you might want to handle wraparound:

# More robust solution with wraparound handling
def replaceDigits(self, s: str) -> str:
    s = list(s)
    for i in range(1, len(s), 2):
        shift_value = int(s[i])
        new_ascii = ord(s[i - 1]) + shift_value
      
        # Handle potential wraparound (though not needed per problem constraints)
        if new_ascii > ord('z'):
            new_ascii = ord('a') + (new_ascii - ord('z') - 1)
      
        s[i] = chr(new_ascii)
    return ''.join(s)

5. Edge Case Handling

Not considering edge cases like empty strings or single character strings:

# Better with edge case handling
def replaceDigits(self, s: str) -> str:
    if len(s) <= 1:  # No digits to replace
        return s
  
    s = list(s)
    for i in range(1, len(s), 2):
        s[i] = chr(ord(s[i - 1]) + int(s[i]))
    return ''.join(s)

Solution: While the problem likely guarantees valid input, adding simple length checks makes the code more robust for real-world applications.

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

Which of the following shows the order of node visit in a Breadth-first Search?


Recommended Readings

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

Load More