Find the Closest Palindrome

profile picture

AfterAcademy Tech

06 Jun 2020

Find the Closest Palindrome

Difficulty: Hard

Asked in: Amazon, Microsoft

Understanding the Problem

Given an integer k, write a program to find the closest integer (not including itself), which is a palindrome.

Problem Note:

  • An integer is said to be a palindrome if it remains the same when its digits are reserved.
  • 'Closest' means that the absolute difference between two integers should be minimum.
  • num is a positive integer represented by a string, whose length will not exceed 15 digits.
  • If two palindromic integers are closest to num and there is a tie between them, then return the smaller one as output.

Example 1

Input: "99"
Output: "101"
Explanation: "88" and "101" are two nearest integers which are palindrome. But "101" is the answer because the absolute difference is minimum between "99" and "101".

Solutions

We will be discussing two approaches for the above problem.

1. Naive approach

As we can see that the closest palindrome to a number can be either less than the number or greater than it. For the greater palindrome, the lower limit is number + 1 while for the lower palindrome, the upper limit is number - 1. So, we move further from the number by one and check if it is palindrome or not. This way we get two palindrome numbers - one lower than the number and one greater than the number. Check which one of them is closest (minimum absolute difference) and return it as an answer.

Pseudo Code

int closestPalindrome(int n)
{
low = n-1

// will decrease the low till low is a palindrome
while(!checkPalindrome(low))
low -= 1

high = n + 1

// will increase the high till high is a palindrome
while(!checkPalindrome(high))
high += 1

// checking difference between both
if ( n - low < high - n)
return low
else
return high
}

Complexity

Time Complexity: O(√N)

Space Complexity: O(1)

2. Efficient Approach

The property of palindrome is the left side of the palindrome is the mirror image of the right side. So, there is a thinking that if we make any of the sides the same as the other, we can achieve our goal.

For example, In the case of “12345”, we mirror “12” to right making it “12321”. Similarly, for 123456, we copy “123” to the right.

Now, the question comes in our mind that which side should we change to make it a palindrome. (Think!)

We can copy the left part of the number to the right to get the closest palindrome. (Why?)

Let’s dive deeper into why we copy the left to right and not the vice-versa. Suppose the number is "abcxy".

First way: Copy the second half to the first half, the new palindrome obtained will be "yxcxy" which has an absolute difference of |10000(a−y)+1000(b−x)| from the original number.

Second way: If we copy the first half to the second half of the string, we get "abcba", which has an absolute difference of |10(x−b)+(y−a)|. Trying to change c additionally, in either case, would incur an additional value of at least 100 in the absolute difference.

Thus, we see that it is always better to copy the left to right in such conditions.

There can be cases where you need to check multiple candidate palindromes by changing the middle digits. For Example

1805170811 

The first half is 18051. After changing the middle digits, the candidates are 1805005081, 1805115081, and 1805225081. The absolute difference is the minimum for 1805225081. Thus, it is the closest palindrome.

How to get these candidate palindromes? (Think!)

We can keep the middle digit same, increment, and decrement the middle digit by 1 and then mirror the left part to get these candidate palindrome numbers.

So, now we know the process to get the closest palindrome, but let's take a look at some corner cases

  • If the number is a single-digit number, the closest palindrome is calculated by decrementing 1 from it.
  • If the number consists of continuous 9 like 99, 999, 9999 ..., then add 2 to it and get the closest palindrome. But in the case of “9”, return 8 as it is single digit and the closest palindrome to it will be 8 and not 11. For example, 99 has the closest palindrome 101
  • If the number is 10, 100, 1000, and so on, subtract 1 from it to get the closest palindrome.

Pseudo Code

int closestPalindrome(int n)
{
if(n < 10)
return n-1
if(check9(n))
return n + 2

s = str(n) // string representation of n

// Take First Half of string

firstHalf = s.substr(0, s.length() /2)

// if string is of odd length we are storing the odd digit
if (s.size() %2)
odd = s[s.size()/2]

// take second half as reverse of first half
secondHalf = reverse(firstHalf)

// store the palindrome candidates

pal1 = "" // for same middle digit
pal2 = "" // for middle -1 digit
pal3 = "" // for middle + 1 digit

if(s.size()%2)
{
// odd length case
pal1 = firstHalf + odd + secondHalf

if(odd == '0')
{
temp = addCarry(firstHalf, -1)
pal2 = temp + "9" + reverse(temp)
} else
pal2 = firstHalf + str(int(odd) -1) + secondHalf

if(odd == '9')
{
temp = addCarry(firstHalf, 1)
pal3 = temp + '0' + reverse(temp)
} else
pal3 = firstHalf + str(int(odd) + 1) + secondHalf
}
else
{
// even length case
pal1 = firstHalf + secondHalf

smallSize = firstHalf.size() // size of first half
if(firstHalf[smallSize -1] == '0')
temp = addCarry(firstHalf,-1)
else
temp = firstHalf.substr(0,smallSize-1) +
str(int(firstHalf[smallSize-1]) - 1)
pal2 = temp + reverse(temp)

if(firstHalf[smallSize-1] == '9')
temp = addCarry(firstHalf, 1)
else
temp = firstHalf.substr(0, smallSize-1) +
str(int(firstHalf[smallSize-1] - 1))

pal3 = temp + reverse(temp)
}

// return the closest
diff1 = abs(n- pal1)
diff2 = abs(n - pal2)
diff3 = abs(n - pal3)

if(int(pal1) == n)
return diff2 <= diff3 ? int(pal2) : int(pal3)
else if(n > int(pal1))
return diff1 <= diff3 ? int(pal1 : int(pal3)
else
return diff2 <= diff1 ? int(pal2) : int(pal1)
}
// Adding carry to num
string addCarry(string num, int carry)
{
if(carry == -1)
{
itr = num.size() -1
while( itr >= 0 && num[i] == '0')
num[itr--] = '9'

if( itr >= 0)
num[itr] = str(int(num[itr])-1)
}
else
{
for(i = num.size() -1 to 0)
{
temp = int(num[i])
num[i] = str((temp + carry)%10)
carry = (temp + carry) / 10
}
}

return num
}

Complexity

Time Complexity: O(No of Digits)(Why?)

Space Complexity: O(No of Digits)(To store the temp variables)

Comparison of different solutions

Suggested problems to solve

  • Check if a number with even number of digits is palindrome or not.
  • Check if a number is a palindrome
  • Check if a number is a palindrome in the octal number system
  • Find next smallest palindrome

Please comment down below for feedback or if you find a better approach!

Happy Coding!

DSA
profile picture
Written by AfterAcademy Tech

Share this article and spread the knowledge