Taro Logo

Lexicographically Smallest Palindrome

Easy
Amazon logo
Amazon
Topics:
StringsTwo Pointers

You are given a string s consisting of lowercase English letters, and you are allowed to perform operations on it. In one operation, you can replace a character in s with another lowercase English letter.

Your task is to make s a palindrome with the minimum number of operations possible. If there are multiple palindromes that can be made using the minimum number of operations, make the lexicographically smallest one.

A string a is lexicographically smaller than a string b (of the same length) if in the first position where a and b differ, string a has a letter that appears earlier in the alphabet than the corresponding letter in b.

Return the resulting palindrome string.

Example 1:

Input: s = "egcfe" Output: "efcfe"

Example 2:

Input: s = "abcd" Output: "abba"

Example 3:

Input: s = "seven" Output: "neven"

Solution


Naive Approach

A brute-force approach would involve generating all possible strings of the same length as the input string s consisting of lowercase English letters and checking if each generated string is a palindrome. Then, among the palindromes, we'd select the lexicographically smallest one that requires the minimum number of operations (character replacements) to transform the original string s into the palindrome.

This approach is highly inefficient and impractical, especially for longer strings, due to the exponential number of possible string combinations.

Time Complexity

The time complexity would be exponential, something like O(26n * n), where n is the length of the string. Generating all possible strings is O(26n). Checking each string for being a palindrome and calculating the number of operations required is O(n).

Space Complexity

The space complexity would also be high, potentially O(26n * n) to store all generated strings.

Optimal Approach

A more efficient approach leverages the properties of palindromes. A palindrome reads the same forwards and backward. Therefore, we can iterate through the input string from both ends simultaneously. If the characters at the two ends are different, we need to make them the same. To obtain the lexicographically smallest palindrome, we should always choose the smaller character to replace the larger character.

Here's a step-by-step breakdown of the algorithm:

  1. Initialize two pointers, left and right, to the start and end of the string, respectively.
  2. Iterate while left < right:
    • If s[left] and s[right] are different:
      • Replace the larger character with the smaller character to minimize the lexicographical order. Specifically:
        • If s[left] < s[right], replace s[right] with s[left].
        • Otherwise, replace s[left] with s[right].
    • Increment left and decrement right.
  3. Return the modified string s.

Example

Let's trace the example s = "egcfe":

  1. left = 0, right = 4. s[0] = 'e', s[4] = 'e'. They are equal, so left++, right--.
  2. left = 1, right = 3. s[1] = 'g', s[3] = 'f'. They are different. Since 'f' < 'g', replace s[1] with 'f'. s becomes "efffe". left++, right--.
  3. left = 2, right = 2. Loop terminates.
  4. Return "efcfe".

Edge Cases

  • Empty string: The algorithm should work correctly for an empty string, returning an empty string.
  • Single-character string: The algorithm should work correctly for a single-character string, returning the same string.
  • Already a palindrome: If the input string is already a palindrome, the algorithm should return the original string.

Code

def make_smallest_palindrome(s):
    s_list = list(s)  # Convert string to list for in-place modification
    left = 0
    right = len(s) - 1

    while left < right:
        if s_list[left] != s_list[right]:
            if s_list[left] < s_list[right]:
                s_list[right] = s_list[left]
            else:
                s_list[left] = s_list[right]
        left += 1
        right -= 1

    return "".join(s_list)  # Convert list back to string

Time Complexity

The time complexity of this optimal approach is O(n), where n is the length of the string s, because we iterate through the string once.

Space Complexity

The space complexity is O(n) because we convert the string to a list of characters for in-place modification. If in-place string modification were possible in the given language, the space complexity could be reduced to O(1).