LeetCode 564. 寻找最近的回文数

380 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。

“最近的”定义为两个整数差的绝对值最小。

本题求的是最近的回文数,何为最近?题目中给出了明确的说法,“最近的”定义为两个整数差的绝对值最小。

举个例子,123最近的回文数为121,因为比123小的回文数为121,比123大的回文数为131,而121与123的差绝对值更小,所以应该得到的结果是121。

先简单思考一下这个问题,对于任意一个数,我们可以先将其直接转为一个回文数,例如:

12345

对于这个数,可以直接通过数的前半部分替换掉后半部分,得到结果:

12321

但你能保证这样得出的结果是最近的回文数吗?在12345的例子中似乎没什么问题,但看下面的例子:

12399

若是直接将其转为回文数,则结果为12321,但是回文数12421显然更接近12399

所以我们应该考虑如下三种情况:

  1. 将整数直接转为回文数
  2. 求得小于该整数的回文数
  3. 求得大于该整数的回文数

得到这三个结果后,再进行差值的比较,然后取差值最小的那个回文数即可。

例如:99321,对于这个数:

  • 首先求得情况一,直接转为回文数,则结果为99399
  • 其次求得情况二,求得小于它的回文数,结果为99299
  • 最后求得情况三,求得大于它的回文数,结果为99499

最后计算差值,9929999321的差值最小,即可得到最终结果。

接下来我们看看如何得到一个数的回文数,以99299为例,首先通过计算数字长度 / 2得到一个下标2,该位置即为数字的中心位置,以该位置为分割,左边部分的数字即为992,那么回文数的产生就是将左边部分的数字反转,得到299,再将其与左边部分数字拼接,得到99299,注意中心位置元素有重复,需要去掉,如下图所示:

image.png

可以用如下方法拼接回文数:

StringBuffer sb = new StringBuffer();
String prefix = String.valueOf(i);
sb.append(prefix);
StringBuffer rightNum = new StringBuffer(prefix).reverse();
// 处理奇偶长度
if (len % 2 == 0) {
    sb.append(rightNum.substring(0));
} else {
    sb.append(rightNum.substring(1));
}
String result = sb.toString();

还需要考虑特殊情况,当数为100时,拼接的回文数结果为9,而对于数字998,拼接后的结果为100001

最后代码如下:

public static String nearestPalindromic(String n) {
    long nu = Long.parseLong(n);
    long ans = Integer.MAX_VALUE;
    long result = 0;
    // 得到所有情况的回文数
    List<Long> list = getHuiWenShu(n);
    // 遍历得到差值最小的
    for (long num : list) {
        long cha = Math.abs(num - nu);
        if(cha < ans){
            // 若回文数为本身,不处理
            if(num != nu){
                result = num;
                ans = cha;
            }
        }
    }
    return Long.toString(result);
}

public static List<Long> getHuiWenShu(String n) {
    int len = n.length();
    // 构造特殊情况回文数
    List<Long> list = new ArrayList<>();
    list.add((long) Math.pow(10, len - 1) - 1);
    list.add((long) Math.pow(10, len) + 1);

    // 获取中心位置左边部分的数字
    long leftNum = Long.parseLong(n.substring(0, (len + 1) / 2));
    // 求得小于、本身、大于 n 的回文数
    for (long i = leftNum - 1; i <= leftNum + 1; i++) {
        StringBuffer sb = new StringBuffer();
        String prefix = String.valueOf(i);
        sb.append(prefix);
        StringBuffer rightNum = new StringBuffer(prefix).reverse();
        // 处理奇偶长度
        if (len % 2 == 0) {
            sb.append(rightNum.substring(0));
        } else {
            sb.append(rightNum.substring(1));
        }
        String result = sb.toString();
        // 保存结果
        list.add(Long.parseLong(result));
    }
    return list;
}

此题得解。