Problem Statement
Brute Force - TLE
class Solution:
def nearestPalindromic(self, n: str) -> str:
number = int(n)
smaller= number - 1
larger = number + 1
def isPalindrome(num):
num_str = str(num)
l, r = 0, len(num_str) - 1
while l < r and num_str[l] == num_str[r]:
l += 1
r -= 1
return num_str[l] == num_str[r]
while not isPalindrome(smaller):
smaller -= 1
while not isPalindrome(larger):
larger += 1
return str(smaller) if number - smaller <= larger - number else str(larger)
Editorial solution
Approach 1: Find Previous and Next Palindromes
class Solution:
def nearestPalindromic(self, n: str) -> str:
len_n = len(n)
i = len_n // 2 - 1 if len_n % 2 == 0 else len_n // 2
first_half = int(n[: i + 1])
"""
Generate possible palindromic candidates:
1. Create a palindrome by mirroring the first half.
2. Create a palindrome by mirroring the first half incremented by 1.
3. Create a palindrome by mirroring the first half decremented by 1.
4. Handle edge cases by considering palindromes of the form 999...
and 100...001 (smallest and largest n-digit palindromes).
"""
possibilities = []
possibilities.append(
self.half_to_palindrome(first_half, len_n % 2 == 0)
)
possibilities.append(
self.half_to_palindrome(first_half + 1, len_n % 2 == 0)
)
possibilities.append(
self.half_to_palindrome(first_half - 1, len_n % 2 == 0)
)
possibilities.append(10 ** (len_n - 1) - 1)
possibilities.append(10**len_n + 1)
diff = float("inf")
res = 0
nl = int(n)
for cand in possibilities:
if cand == nl:
continue
if abs(cand - nl) < diff:
diff = abs(cand - nl)
res = cand
elif abs(cand - nl) == diff:
res = min(res, cand)
return str(res)
def half_to_palindrome(self, left: int, even: bool) -> int:
res = left
if not even:
left = left // 10
while left > 0:
res = res * 10 + left % 10
left //= 10
return res
Approach 2: Binary Search
class Solution:
def convert(self, num: int) -> int:
s = str(num)
n = len(s)
l, r = (n - 1) // 2, n // 2
s_list = list(s)
while l >= 0:
s_list[r] = s_list[l]
r += 1
l -= 1
return int("".join(s_list))
def previous_palindrome(self, num: int) -> int:
left, right = 0, num
ans = float("-inf")
while left <= right:
mid = (right - left) // 2 + left
palin = self.convert(mid)
if palin < num:
ans = palin
left = mid + 1
else:
right = mid - 1
return ans
def next_palindrome(self, num: int) -> int:
left, right = num, int(1e18)
ans = float("-inf")
while left <= right:
mid = (right - left) // 2 + left
palin = self.convert(mid)
if palin > num:
ans = palin
right = mid - 1
else:
left = mid + 1
return ans
def nearestPalindromic(self, n: str) -> str:
num = int(n)
a = self.previous_palindrome(num)
b = self.next_palindrome(num)
if abs(a - num) <= abs(b - num):
return str(a)
return str(b)