LeetCode-整数反转

756 阅读3分钟

原题链接

题目

给出一个 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 可实现,另一种则是通过数学的方法,找寻范围取值的规律进行处理。

关于整数的两种处理方式

解题过程以及踩坑经历

  1. 使用 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;
		}
    }
}
  1. 踩坑经历: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

  1. 数学的方式处理, [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,不能算是真正意义上的正解。