原题链接
题目
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [231, 231− 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
题目解析
- 可以将输入的32位有符号整数当做栈来处理,栈拥有先进后出的特点,例如 123 的进栈顺序是 1 -> 2 -> 3,那么出栈的顺序则是 3 -> 2 -> 1,这种处理方式只需要一次循坏就可以实现反转
- 题目的难点在于数值溢出的处理,如果使用 JAVA 的话,处理的方式就有两种,一种是字符串转换成 Integer 的时候,如果数值溢出就会抛出 NumberFormatException 的异常,通过 try-catch 捕捉返回 0 可实现,另一种则是通过数学的方法,找寻范围取值的规律进行处理。
关于整数的两种处理方式
解题过程以及踩坑经历
- 使用 StringBuffer + 捕捉异常
基于第一种的解决方案,最为简单粗暴的方法,也是最 Low 的方法,就是使用 StringBuffer 提供的 reserve 方法,直接将整数加入 StringBuffer 进行反转处理,如果是负整数,则还需要将反转后的 "-" 移动到字符串行首,再转换成 Integer,如果数值溢出,则会抛出 NumberFormatException 的异常,捕捉异常以后返回 0
class Solution {
public int reverse(int x) {
StringBuffer stringBuffer = new StringBuffer();
try{
stringBuffer.append(x);
return Integer.valueOf(
x > 0 ? stringBuffer.reverse().toString() :
stringBuffer.charAt(0) + stringBuffer.reverse().substring(0,stringBuffer.length() - 1).toString()
);
}catch (NumberFormatException e){
return 0;
}
}
}
- 踩坑经历:JAVA数值相加溢出不抛出异常,直接进行截断处理
先进后出的方式反转整数,如果此时输入的值反转后会导致溢出,以下方法的JAVA处理不会抛出异常,而是直接转换为 二进制截断为32位
class Solution {
public int reverse(int x) {
int number = 0;
try{
while(x != 0){
int pop = x % 10;
x /= 10;
number = 10 * number + pop;
}
return number;
}catch (Exception e){
return 0;
}
}
}
例如输入 1534236469 ,预期反转以后溢出输出 0,结果却是 1056389759,下面通过计算器进行分析
此时的 BIN 二级制是 36位,如果截断为32位,则是 1056389758,这个时候加上最后的 1 就输出 1056389759
- 数学的方式处理, [231, 231− 1] 也就是 (-2147483648 ~ 2147483647),取值范围是10位数,那么可以对位数进行判断,如果超出 10 位数则判定为溢出,如果是 10 位数,判断是否在取值范围内,由于采用 先进后出的方式,则最后只需要判断 第 10 位 正数是否超过 7 ,负数是否 小于 -8 即可。
// 官方正解
class Solution {
public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 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;
}
return rev;
}
}
总结
- 数学的处理方式所用时间要小于 StringBuffer + try-catch 的处理方式,而且第一种方式依赖 JAVA,不能算是真正意义上的正解。