Taro Logo

Lexicographically Smallest Palindrome

Easy
2 views
a month ago

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. Return the resulting palindrome string.

For example:

  • If s = "egcfe", the output should be "efcfe"
  • If s = "abcd", the output should be "abba"
  • If s = "seven", the output should be "neven"

Write a function that takes a string s as input and returns the lexicographically smallest palindrome that can be made from s with the minimum number of operations. Describe the time and space complexity of your solution. Discuss any potential edge cases and how your code handles them.

Sample Answer
def make_smallest_palindrome(s):
    n = len(s)
    s_list = list(s)
    
    for i in range(n // 2):
        if s_list[i] != s_list[n - 1 - i]:
            if s_list[i] < s_list[n - 1 - i]:
                s_list[n - 1 - i] = s_list[i]
            else:
                s_list[i] = s_list[n - 1 - i]
                
    return "".join(s_list)

# Example usage and tests:

# Example 1
s = "egcfe"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Example 2
s = "abcd"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Example 3
s = "seven"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 4: already a palindrome
s = "aba"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 5: empty string (although constraint says len >= 1, let's handle it)
s = ""
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 6: single character string
s = "a"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 7: longer string
s = "racecar"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 8
s = "google"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 9
s = "leetcode"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

# Test case 10
s = "rotor"
print(f"Input: {s}, Output: {make_smallest_palindrome(s)}")

Naive Approach

A brute force approach would involve generating all possible strings that differ from the input string by a certain number of operations (character replacements) and then checking if each generated string is a palindrome. From the palindromes, choose the lexicographically smallest one. This approach is highly inefficient due to the vast number of possible string combinations, making it impractical for strings of significant length.

Optimal Approach

The optimal approach is to iterate through the string from both ends towards the center. At each pair of characters (s[i] and s[n-1-i]), if they are different, replace the larger character with the smaller one. This ensures that the resulting string is both a palindrome and lexicographically the smallest possible.

Big(O) Run-time Analysis

  • The algorithm iterates through the first half of the string once. Therefore, the time complexity is O(n), where n is the length of the string.

Big(O) Space Usage Analysis

  • The algorithm uses a list to store the characters of the string. This list has the same length as the input string. Therefore, the space complexity is O(n).

Edge Cases

  • Empty String: The code handles the empty string gracefully, although based on the problem constraints, the input string will never be empty, but it's good to keep in mind.
  • Single Character String: A single-character string is already a palindrome, so the algorithm returns the string as is.
  • Already a Palindrome: If the input string is already a palindrome, the algorithm doesn't modify it and returns the original string.
  • Strings with Even and Odd Lengths: The algorithm works correctly for both even and odd length strings because the loop condition range(n // 2) ensures that the middle character of an odd length string is not processed.
  • Strings with Mixed Case: The code assumes the string contains only lowercase English letters as the problem states. If it contains upper case or other characters, the code will give unexpected results. A good approach would be to convert any input to lowercase before applying the logic.