Given a string n
representing an integer, return the closest integer (not including itself), which is a palindrome. If there is a tie, return the smaller one.
The closest is defined as the absolute difference minimized between two integers.
Example 1:
Input: n = "123" Output: "121"
Example 2:
Input: n = "1" Output: "0" Explanation: 0 and 2 are the closest palindromes but we return the smallest which is 0.
Constraints:
1 <= n.length <= 18
n
consists of only digits.n
does not have leading zeros.n
is representing an integer in the range [1, 1018 - 1]
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the closest palindrome involves checking many possibilities around the original number. It's like trying out many slight variations of the number to see if any of them are palindromes and, if so, which is closest.
Here's how the algorithm would work step-by-step:
def find_closest_palindrome_brute_force(number):
smaller_palindrome = None
larger_palindrome = None
original_number = number
current_number = original_number - 1
while smaller_palindrome is None and current_number >= 0:
if str(current_number) == str(current_number)[::-1]:
smaller_palindrome = current_number
current_number -= 1
current_number = original_number + 1
while larger_palindrome is None:
if str(current_number) == str(current_number)[::-1]:
larger_palindrome = current_number
current_number += 1
# Need to handle edge cases where one palindrome doesn't exist
if smaller_palindrome is None:
return larger_palindrome
if larger_palindrome is None:
return smaller_palindrome
smaller_difference = abs(original_number - smaller_palindrome)
larger_difference = abs(larger_palindrome - original_number)
# If both are equally close, choose the smaller one
if smaller_difference <= larger_difference:
return smaller_palindrome
# Otherwise return the larger one
return larger_palindrome
The trick is to find nearby palindromes instead of checking every single number. We only need to consider a few special cases based on the input number's structure to find the closest palindrome efficiently.
Here's how the algorithm would work step-by-step:
def find_the_closest_palindrome(number):
number_as_string = str(number)
number_length = len(number_as_string)
# Handle single-digit numbers
if number_length == 1:
return number - 1
candidates = []
# Create palindrome by mirroring the first half
first_half = number_as_string[:(number_length + 1) // 2]
palindrome_a = first_half + first_half[:number_length // 2][::-1]
candidates.append(int(palindrome_a))
# Create palindrome by incrementing first half
first_half_incremented = str(int(first_half) + 1)
# Need to handle carry when incrementing
if len(first_half_incremented) > len(first_half):
palindrome_b = str(1) + '0' * (number_length - 1) + str(1)
else:
palindrome_b = first_half_incremented + first_half_incremented[:number_length // 2][::-1]
candidates.append(int(palindrome_b))
# Create palindrome by decrementing first half
first_half_decremented = str(int(first_half) - 1)
# Need to handle borrow when decrementing
if first_half_decremented == '-1':
palindrome_c = '9' * (number_length - 1)
else:
palindrome_c = first_half_decremented + first_half_decremented[:number_length // 2][::-1]
candidates.append(int(palindrome_c))
# Add edge cases to consider
candidates.append(10**(number_length - 1) - 1)
candidates.append(10**number_length + 1)
closest_palindrome = -1
min_difference = float('inf')
# Find the closest palindrome
for candidate in candidates:
difference = abs(number - candidate)
# Tiebreaker goes to the smaller number
if difference < min_difference:
min_difference = difference
closest_palindrome = candidate
elif difference == min_difference:
closest_palindrome = min(closest_palindrome, candidate)
return closest_palindrome
Case | How to Handle |
---|---|
Null or empty input string | Return an empty string or throw an IllegalArgumentException, depending on problem specification. |
Single-character input string | Return the input string itself, as a single character is a palindrome. |
Input string is already a palindrome | Return the original input string itself as it is already the closest. |
Input string consists of all 9's (e.g., '999') | Incrementing this number will result in a number with one more digit (e.g., 1001), handle string manipulation to construct the appropriate palindrome. |
Input string is a large number (potential for integer overflow during conversion) | Use string manipulation instead of integer conversions to avoid overflow issues. |
Input string is close to the maximum integer value represented as a string. | Handle potential overflow in the increment/decrement palindrome generation steps by doing string arithmetic. |
Number has leading zeros (e.g., "00121"). | Ensure leading zeros are considered when finding the nearest palindrome and construct the resulting palindrome properly or trim leading zeros if appropriate for output. |
Input string represents a negative number. | If negative numbers are invalid input, throw an exception; otherwise, consider the absolute value and add the negative sign back to the closest palindrome if appropriate, or specify that only positive integers should be processed. |