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"
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.
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).
The space complexity would also be high, potentially O(26n * n) to store all generated strings.
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:
left
and right
, to the start and end of the string, respectively.left < right
:
s[left]
and s[right]
are different:
s[left] < s[right]
, replace s[right]
with s[left]
.s[left]
with s[right]
.left
and decrement right
.s
.Let's trace the example s = "egcfe"
:
left = 0
, right = 4
. s[0] = 'e'
, s[4] = 'e'
. They are equal, so left++
, right--
.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--
.left = 2
, right = 2
. Loop terminates.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
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.
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).