Find the Closest Palindrome

HARD

Description

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].

Approaches

Checkout 2 different approaches to solve Find the Closest Palindrome. Click on different approaches to view the approach and algorithm in detail.

Brute Force by Checking Neighbors

This approach involves converting the input string n to a number and then iteratively checking numbers smaller and larger than n until a palindrome is found in each direction. The one with the smaller absolute difference to n is the answer.

Algorithm

  • Convert the input string n to a long variable num.
  • Find the first palindrome smaller than num:
    • Initialize lower = num - 1.
    • Loop downwards from lower, checking if each number is a palindrome.
    • A number is checked by converting it to a string and verifying if the string is the same forwards and backward.
    • Stop when the first smaller palindrome is found.
  • Find the first palindrome larger than num:
    • Initialize upper = num + 1.
    • Loop upwards from upper, checking if each number is a palindrome.
    • Stop when the first larger palindrome is found.
  • Compare the absolute differences: |num - lower| and |upper - num|.
  • If |num - lower| is less than or equal to |upper - num|, return lower. Otherwise, return upper.
  • Convert the result back to a string.

The brute-force method is the most straightforward way to conceptualize the problem. The core idea is to search outwards from the given number n in both directions (decreasing and increasing) and stop at the very first palindrome encountered on each side.

  1. Conversion: The input string n is first converted into its numerical representation (e.g., a long in Java) to allow for arithmetic operations.
  2. Downward Search: We start a search for the largest palindrome that is smaller than n. This is done by initializing a variable lower to n - 1 and decrementing it in a loop. In each iteration, we check if lower is a palindrome. The first number that satisfies this condition is our first candidate.
  3. Upward Search: Similarly, we search for the smallest palindrome that is larger than n. We initialize upper to n + 1 and increment it until we find a palindrome.
  4. Comparison: After finding both lower and upper palindromes, we determine which one is closer to n by comparing the absolute differences n - lower and upper - n. According to the problem statement, if the differences are equal (a tie), we must choose the smaller palindrome, which is lower.
  5. Result: The chosen number is then converted back to a string and returned.

To check if a number is a palindrome, a helper function is used. It converts the number to a string and checks if the string reads the same forwards and backward, typically by using a two-pointer technique.

class Solution {
    public String nearestPalindromic(String n) {
        long num = Long.parseLong(n);
        long lower = findLowerPalindrome(num - 1);
        long upper = findUpperPalindrome(num + 1);

        long diff1 = num - lower;
        long diff2 = upper - num;

        if (diff1 <= diff2) {
            return String.valueOf(lower);
        } else {
            return String.valueOf(upper);
        }
    }

    private long findLowerPalindrome(long limit) {
        long i = limit;
        while (true) {
            if (isPalindrome(String.valueOf(i))) {
                return i;
            }
            i--;
        }
    }

    private long findUpperPalindrome(long limit) {
        long i = limit;
        while (true) {
            if (isPalindrome(String.valueOf(i))) {
                return i;
            }
            i++;
        }
    }

    private boolean isPalindrome(String s) {
        int left = 0;
        int right = s.length() - 1;
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

Complexity Analysis

Time Complexity: O(10^(L/2) * L), where L is the length of `n`. The gap between a number and its nearest palindrome can be on the order of `10^(L/2)`. For each number in this gap, we perform a palindrome check which takes O(L) time. This complexity is too high for the given constraints.Space Complexity: O(L), where L is the number of digits in `n`. This space is used to store the string representation of the numbers being checked.

Pros and Cons

Pros:
  • Simple to understand and implement.
  • Logically straightforward.
Cons:
  • Highly inefficient for larger inputs as the distance to the nearest palindrome can be large.
  • Will likely result in a 'Time Limit Exceeded' error on most platforms for the given constraints.

Code Solutions

Checking out 4 solutions in different languages for Find the Closest Palindrome. Click on different languages to view the code.

class Solution {
public
  String nearestPalindromic(String n) {
    long x = Long.parseLong(n);
    long ans = -1;
    for (long t : get(n)) {
      if (ans == -1 || Math.abs(t - x) < Math.abs(ans - x) ||
          (Math.abs(t - x) == Math.abs(ans - x) && t < ans)) {
        ans = t;
      }
    }
    return Long.toString(ans);
  }
private
  Set<Long> get(String n) {
    int l = n.length();
    Set<Long> res = new HashSet<>();
    res.add((long)Math.pow(10, l - 1) - 1);
    res.add((long)Math.pow(10, l) + 1);
    long left = Long.parseLong(n.substring(0, (l + 1) / 2));
    for (long i = left - 1; i <= left + 1; ++i) {
      StringBuilder sb = new StringBuilder();
      sb.append(i);
      sb.append(new StringBuilder(i + "").reverse().substring(l & 1));
      res.add(Long.parseLong(sb.toString()));
    }
    res.remove(Long.parseLong(n));
    return res;
  }
}

Video Solution

Watch the video walkthrough for Find the Closest Palindrome



Patterns:

Math

Data Structures:

String

Companies:

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.