力扣 564. 寻找最近的回文数

该博客探讨了一种解决LeetCode问题——寻找给定整数的最近回文数的方法。通过分析如何翻转和调整数字的前半部分来生成可能的回文数,同时考虑了位数增加和减少的影响。文章详细解释了代码实现,包括获取可能的候选回文数的策略,并给出了具体的代码示例。

题目来源:https://leetcode-cn.com/problems/find-the-closest-palindrome/

大致题意:
给一个字符串表示的整数 n,以字符串形式返回与 n 之间差值最小的回文数(不能为其本身,有多个答案返回最小的)

思路

若要构造与原数差别尽可能小的回文数,可以直接将原数高位部分翻转替换低位部分,如 12345,取出高位 12,翻转为 21,替换低位 45,结果为 12321

但是这样翻转不一定是离原数最近的回文数,如 86201,翻转为 86268,但是事实上回文数 86168 离原数更近。
可见,这种情况下,翻转后的数大于原数,但是最近的回文数可能是前半部分 862 - 1 = 861 翻转后的结果。

相似的,12399 直接翻转后为 12321,但是最近的回文数是 12421。
可见,这种情况下,翻转后的数小于原数,但是最近的回文数可能是前半部分 123 + 1 = 124 翻转后的结果

但是只考虑将前半部分加 1、减 1和直接翻转 有时候也无法找到符合题意的最近回文数

  • 如 1000,前半部分 10,减 1 翻转后为 99,加 1 翻转后为 1111,直接翻转为 1001。但是事实上最近回文数还有 999,小于 1001,所以 999 才是所求答案
  • 如 999,减 1 翻转后为 989,加 1 翻转后为 10001,直接翻转为 999(为本身,不符合题意)。符合题意的最近回文数为 1001.

所以必须考虑前半部分加 1、减 1造成数的位数增加、减少的影响

  • 可以通过每次将数对应长度位数减 1 的 99…99,和位数加 1 的 100…001放入候选的最近回文数避免这个问题
  • 如原数 12345,位数为 5,那么就放入 9999(104 - 1)和 100001(105 + 1)

代码:

public class NearestPalindromic {
    public String nearestPalindromic(String n) {
        List<Long> candidates = getCandidates(n);
        long num = Long.parseLong(n);
        long ans = candidates.get(0);
        long min = Math.abs(num - ans);
        // 找出与原数的差值绝对值最小的数
        for (int i = 1; i < candidates.size(); i++) {
            if (candidates.get(i) == num) {
                continue;
            }
            long cur = Math.abs(num - candidates.get(i));
            if (cur < min) {
                ans = candidates.get(i);
                min = cur;
            } else if (cur == min) {
                ans = candidates.get(i) > ans ? ans : candidates.get(i);
            }
        }
        return String.valueOf(ans);
    }

    public List<Long> getCandidates(String n) {
        List<Long> candidates = new ArrayList<>();
        int len = n.length();
        // 中间位 +1 后可能导致位数增加,存下可能有的增位数
        candidates.add((long) Math.pow(10, len) + 1);
        // 中间位 -1 后可能导致位数减少,存下可能有的减位数
        candidates.add((long) Math.pow(10, len - 1) - 1);
        // 取数字的前一半
        String prefix = n.substring(0, (len + 1) / 2);
        long prefixNum = Long.parseLong(prefix);
        // 遍历三种回文数,减少中间部分、中间部分不变、增加中间部分
        for (long i = prefixNum - 1; i <= prefixNum + 1; i++) {
            StringBuffer sb = new StringBuffer();
            // 添加前半部分
            sb.append(i);
            StringBuffer suffix = new StringBuffer();
            suffix.append(i).reverse();
            // 添加后半部分
            // 若原数字长度为奇数,那么后半部分要比前半部分长度 -1
            sb.append(suffix.substring(len & 1));
            candidates.add(Long.parseLong(sb.toString()));
        }
        return candidates;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值