7.整数反转

79 阅读2分钟

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

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

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

先上代码:

版本1:

public class Problem_0007_ReverseInteger {
    public static int reverse(int x) {
        //按照负数算,负数取正数永远大一位。int类型的取值范围-2147483648~2147483647
        int p = x;
        x = x > 0 ? -x : x;
        int res = 0;
        while (x != 0) {
            res = res * 10 + x % 10;
            x /= 10;
        }
        return p < 0 ? res : Math.abs(res);
    }
}

存在问题,没有做溢出判断,比如x的值为2147483647,数字反转后大于int类型的最大值肯定会溢出

版本2:

public class Problem_0007_ReverseInteger {
    public static int reverse(int x) {
        //按照负数算,负数取正数永远大一位。int类型的取值范围-2147483648~2147483647
        int p = x;
        boolean neg = ((x >>> 31) & 1) == 1;
        x = neg ? x : -x;
        int m = Integer.MIN_VALUE / 10;
        int n = Integer.MIN_VALUE % 10;
        int res = 0;
        while (x != 0) {
            if (res < m || (res == m && x % 10 < n)) {
                return 0;
            }
            res = res * 10 + x % 10;
            x /= 10;
        }
        return p < 0 ? res : Math.abs(res);
    }
}

判断一个数是正数还是负数,位运算比简单的三元运算符效率更高。

以上有两个需要解释的位置:

  1. boolean neg = ((x >>> 31) & 1) == 1;用来判断x是否为正数,关于位运算,参考博客:blog.csdn.net/jiangyi711/…

    因为int是带符号类型,所以最高位为符号位,于是最大表示的正数是:01111111 11111111 11111111 11111111,也就是2的31次方减1。 再来看最小值,-2的31次方的原码表示为10000000 00000000 00000000 00000000,此时最高位的数字既代表符号,也代表数值。求它的补码,所得结果为10000000 00000000 00000000 00000000。同样也是最高位既代表符号又代表数值,也就是说-2的31次方的原码和补码是相同的。

    image-20240104133004660

  2. 反转整数后防止溢出

    if (res < m || (res == m && x % 10 < n)) {
        return 0;
    }
    

    res < m : 当在反转的过程中res < -214748364,此时再反转肯定会溢出int接受范围。

    res == m && x % 10 < n : 当在反转的过程中res == -214748364,但是x % 10 < 8 此时再反转肯定也会溢出int接受范围。

    image-20240104133511737