LeetCode题练习与总结:寻找最近的回文数--564

一、题目描述

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

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

示例 1:

输入: n = "123"
输出: "121"

示例 2:

输入: n = "1"
输出: "0"
解释: 0 和 2是最近的回文,但我们返回最小的,也就是 0。

提示:

  • 1 <= n.length <= 18
  • n 只由数字组成
  • n 不含前导 0
  • n 代表在 [1, 10^18 - 1] 范围内的整数

二、解题思路

  • 根据题意,我们需要找到与给定整数最近的回文整数。首先,我们可以生成一些候选的回文整数,然后比较它们与给定整数的差值,找到差值最小的回文整数。

  • 候选的回文整数可以从以下几种情况生成:

    • 将原整数的左半部分反转,与原整数的左半部分拼接,形成一个新的回文整数。
    • 将原整数的左半部分反转,与原整数的左半部分拼接,然后分别减一和加一,形成两个新的回文整数。
    • 当整数的长度为1时,最近的回文整数为0。
    • 当整数为10的幂时,最近的回文整数为10的幂减一。
  • 比较这些候选的回文整数与原整数的差值,找到差值最小的回文整数。如果有多个差值相同,返回较小的那个。

三、具体代码

import java.util.ArrayList;
import java.util.List;

class Solution {
    public String nearestPalindromic(String n) {
        int len = n.length();
        // 生成候选的回文整数列表
        List candidates = new ArrayList<>();
        // 特殊情况:长度为1,最近的回文整数为0
        if (len == 1) {
            return "0";
        }
        // 特殊情况:整数为10的幂
        if (isPowerOfTen(n)) {
            return String.valueOf((long)Math.pow(10, len - 1) - 1);
        }

        // 候选1:左半部分反转拼接
        String leftPart = n.substring(0, (len + 1) / 2);
        long leftNum = Long.parseLong(leftPart);
        for (long i = leftNum - 1; i <= leftNum + 1; i++) {
            String prefix = String.valueOf(i);
            String candidate = prefix + new StringBuilder(prefix).reverse().substring(len & 1);
            candidates.add(Long.parseLong(candidate));
        }
        // 去除自身
        candidates.remove(Long.parseLong(n));

        // 比较差值,找到最近的回文整数
        long diff = Long.MAX_VALUE;
        long nearest = 0;
        long num = Long.parseLong(n);
        for (long candidate : candidates) {
            long curDiff = Math.abs(candidate - num);
            if (curDiff < diff || (curDiff == diff && candidate < nearest)) {
                diff = curDiff;
                nearest = candidate;
            }
        }
        return String.valueOf(nearest);
    }

    // 判断是否为10的幂
    private boolean isPowerOfTen(String n) {
        return n.matches("10+");
    }
}

以上代码实现了找到与给定整数最近的回文整数的功能。首先生成了几个候选的回文整数,然后比较它们与原整数的差值,找到最近的回文整数。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 计算字符串长度 len:O(1)
  • 特殊情况判断(长度为1和是否为10的幂):
    • 判断长度是否为1:O(1)
    • 判断是否为10的幂:使用正则表达式,最坏情况下O(n),其中n为字符串的长度
  • 生成候选回文整数:
    • 循环次数固定为3次:O(1)
    • 每次循环中,将字符串转换为数字:O(m),其中m为字符串的长度的一半(左半部分)
    • 每次循环中,字符串反转和拼接:O(m)
    • 因此,这部分的总时间复杂度为O(3m) = O(m)
  • 移除自身:O(m),因为需要遍历列表并比较字符串
  • 比较差值找到最近的回文整数:O(3),因为候选列表的大小固定为3
    • 比较操作:O(1)
    • 因此,这部分的总时间复杂度为O(3) = O(1)

综合以上分析,时间复杂度主要取决于字符串长度的一半(m),所以总的时间复杂度为O(m)。

2. 空间复杂度
  • 候选回文整数列表:固定大小为3,所以空间复杂度为O(1)
  • 临时变量:包括字符串和数字,这些变量使用的空间不随输入大小变化,所以空间复杂度为O(1)

综合以上分析,空间复杂度为O(1),即常数空间复杂度。

五、总结知识点

  • 字符串操作

    • substring(int beginIndex, int endIndex):获取字符串的子串。
    • length():获取字符串的长度。
    • StringBuilder:用于构建字符串,支持反转操作。
  • 数学操作

    • Math.pow(double a, double b):计算a的b次幂。
    • Long.parseLong(String s):将字符串转换为长整型数字。
  • 循环和条件判断

    • for 循环:用于迭代固定次数。
    • if 和 else:用于条件判断。
    • while 循环(尽管在这个代码中没有直接使用,但它是基本的循环结构之一)。
  • 集合操作

    • ArrayList:动态数组,用于存储候选回文整数。
    • add(E e):向集合中添加元素。
    • remove(Object o):从集合中移除特定元素。
  • 正则表达式

    • matches(String regex):用于检查字符串是否与给定的正则表达式匹配。
  • 位操作

    • 使用位与操作符 & 来确定字符串长度是奇数还是偶数,从而决定如何拼接回文整数。
  • 逻辑和算法

    • 创建回文整数的逻辑:通过反转字符串的一半并拼接来生成候选回文整数。
    • 比较算法:通过比较差值来找到最近的回文整数。
  • 常量

    • Long.MAX_VALUE:Java中长整型的最大值,用于初始化差值变量。
  • 基本类型和包装类型

    • 使用基本类型 long 和其包装类型 Long 进行数值操作。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

你可能感兴趣的:(LeetCode,Java,困难,算法,数据结构,LeetCode,Java,数学,字符串,职场和发展)