首页 简历|笔试面试

7.整数反转

  • 25年9月4日 发布
  • 349.59KB 共6页
7.整数反转7.整数反转7.整数反转7.整数反转7.整数反转

7. 整数反转

二哥的 LeetCode 题解真的精辟——鲁迅(我没说)

题意

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例

输入:x = 123

输出:321

输入:x = -123

输出:-321

输入:x = 120

输出:21

输入:x = 0

输出:0

难度

中等

分析 1

看到这题,我的第一感觉就是把 32 位的整数看成是一个字符串,然后直接调用

StringBuilder 的 reverse 方法,这样就可以完成反转了,对吧,完全可行。

剩下需要做的,就是处理一下负数的情况,还有超出边界的情况。

class Solution {

public int reverse(int x) {

String reversed = new

StringBuilder().append(Math.abs(x)).reverse().toString();

try {

// 如果原始整数为负数,则反转后的结果也应该是负数

int result = Integer.parseInt(reversed);

return (x < 0) ? result * -1 : result;

} catch (NumberFormatException e) {

// 捕获溢出异常并返回 0

return 0;

}

}

}

①、Math.abs() 方法可以获取一个数的绝对值,比如 Math.abs(-123)的结果就是 123。

②、然后用 StringBuilder 的 append 方法将正数添加到字符串序列中。

③、调用 reverse 方法将字符串反转。我在《二哥的 Java 进阶之路》里曾讲过 reverse 方

法,没看过源码的球友可以回头看一眼。

int n = count - 1; // 字符序列的最后一个字符的索引

// 遍历字符串的前半部分,`(n-1) >> 1` 是 `(n-1) / 2` 的位运算表示,也就是字符串的前半部

分的最后一个字符的索引。

for (int j = (n-1) >> 1; j >= 0; j--) {

int k = n - j; // 计算相对于 j 对称的字符的索引

char cj = value[j]; // 获取当前位置的字符

char ck = value[k]; // 获取对称位置的字符

value[j] = ck; // 交换字符

value[k] = cj; // 交换字符

}

这个翻转的方法其实非常巧妙,从字符串的两端开始交换,直到中间位置,比从头到尾或

者从尾到头要快一倍。

④、最后调用 Integer 的 parseInt 方法将字符串转换成整数,如果超出边界,就会抛出

NumberFormatException 异常,我们通过 try-catch 捕获这个异常,然后返回 0。如果是

负数,就将结果乘以 -1。

来看一下题解的效率:

007.%E6%95%B4%E6%95%B0%E5%8F%8D%E8%BD%AC-20231228125411.png

还不错,那其实我们可以再优化一下,不调用 StringBuilder 的 reverse 方法,我们可以自

己实现一个翻转的方法,把 reverse 方法的源码拿过来改一改就行了。

class Solution {

public int reverse(int x) {

String reversed = reverseString(String.valueOf(Math.abs(x)));

try {

// 如果原始整数为负数,则反转后的结果也应该是负数

int result = Integer.parseInt(reversed);

return (x < 0) ? result * -1 : result;

} catch (NumberFormatException e) {

// 捕获溢出异常并返回 0

return 0;

}

}

private String reverseString(String s) {

char[] value = s.toCharArray();

int n = value.length - 1;

for (int j = (n-1) >> 1; j >= 0; j--) {

int k = n - j;

char cj = value[j];

char ck = value[k];

value[j] = ck;

value[k] = cj;

}

return new String(value);

}

}

只不过,这样做的意义不大,换汤不换药而已,有没有更好的方法呢?

分析 2

对于一个整数来说,我们可以通过取余和除法来获取它的每一位,比如 123,我们通过

123 % 10 来获取它的个位 3,123 / 10 来把它的个位去掉,剩下 12;

然后通过 12 % 10 来获取它的十位 2,12 / 10 来把它的十位去掉,剩下 1;

然后再通过 1 % 10 来获取它的百位 1,1 / 10 来把它的百位去掉,剩下 0,这样就把整数

的每一位都获取到了,获取知道就很好处理了,不断地乘以 10 累加就行了。

007.%E6%95%B4%E6%95%B0%E5%8F%8D%E8%BD%AC-20231228132251.png

唯一需要注意的就是判断一下是否超出边界,这里我用了一个小技巧,就是在每次累加之

前,先判断一下累加后的结果是否超出边界,如果超出边界,就直接返回 0,否则再累

加。

class Solution {

public int reverse(int x) {

int rev = 0; // 用于存储反转后的结果

while (x != 0) {

int pop = x % 10; // 获取 x 的最后一位数字

x /= 10; // 移除 x 的最后一位数字

// 检查溢出:如果 rev > Integer.MAX_VALUE/10 或 rev <

Integer.MIN_VALUE/10,则会溢出

if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 &&

pop > 7)) return 0;

if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 &&

pop < -8)) return 0;

rev = rev * 10 + pop; // 将 pop 添加到 rev 的最后

}

return rev; // 返回反转后的整数

}

}

①、rev == Integer.MAX_VALUE / 10 && pop > 7

• Integer.MAX_VALUE 是 2147483647,Integer.MAX_VALUE / 10 则是

214748364。

• 当 rev 等于 214748364 时,乘以 10 再加上任何大于 7 的数字将导致整数溢出,比

如说 214748364 * 10 + 8 = 2147483648 > Integer.MAX_VALUE(2147483647)。

②、rev == Integer.MIN_VALUE / 10 && pop < -8

• Integer.MIN_VALUE 是 -2147483648,Integer.MIN_VALUE / 10 则是

-214748364。

• 当 rev 等于 -214748364 时,乘以 10 再减去任何小于 -8 的数字将导致整数溢出,比

如说 -214748364 * 10 - 9 = -2147483649 < Integer.MIN_VALUE(-2147483648)。

那如果说,写题解的时候,不想出现这种魔法数字(7 或者 -8),可以这样写:

class Solution {

public int reverse(int x) {

int rev = 0; // 用于存储反转后的结果

while (x != 0) {

int pop = x % 10; // 获取 x 的最后一位数字

x /= 10; // 移除 x 的最后一位数字

// 检查溢出:如果 rev > Integer.MAX_VALUE/10 或 rev <

Integer.MIN_VALUE/10,则会溢出

if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 &&

pop > Integer.MAX_VALUE % 10)) return 0;

if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 &&

pop < Integer.MIN_VALUE % 10)) return 0;

rev = rev * 10 + pop; // 将 pop 添加到 rev 的最后

}

return rev; // 返回反转后的整数

}

}

运行效率也非常喜人,直接击败 100% 的 Java 提交者。

007.%E6%95%B4%E6%95%B0%E5%8F%8D%E8%BD%AC-20231228132440.png

总结

这道题其实算不上中等的难度,不论是直接调用 reverse 还是通过取余和除法来获取每一

位,都是比较容易想到的方法,唯一需要考虑的就是边界问题。

力扣链接:https://leetcode.cn/problems/reverse-integer/submissions/

学过基本数据类型的球友应该知道,Java 中的整数类型有 4 种,分别是 byte、short、int

和 long,它们的取值范围如下:

类型

byte

short

int

long

其中 int 类型的取值范围就是 32 位的有符号整数的取值范围,所以我们可以把 int 类型的

最大值和最小值作为边界来判断是否溢出。

32 位的有符号整数的取值范围是从 -2^31 到 2^31 - 1,其中一位用于表示符号(正或

负),剩下的 31 位用于表示数值,这意味着其范围是 -2,147,483,648(即 -2^31)到

2,147,483,647(即 2^31 - 1)。

在二进制系统中,每个位(bit)可以表示两个状态,通常是 0 和 1。对于 32 位得正二进

制数,除去符号位,从右到左的每一位分别代表 2^0, 2^1, 2^2, …, 2^30,这个二进制数转

换为十进制就是 2^0 + 2^1 + 2^2 + … + 2^30,也就是 2,147,483,647。

第一种题解很容易想到,涉及到的知识点有:

• StringBuilder

• String

• 基本数据类型的包装器

• 异常处理

第二种题解也不难想到,主要就是除法和取余的运算,以及边界的判断,涉及到的知识点

有:

• 基本数据类型

• 运算符

• 流程控制

开通会员 本次下载免费

所有资料全部免费下载! 推荐用户付费下载获取返佣积分! 积分可以兑换商品!
一键复制 下载文档 联系客服