LeetCode刷题之旅【简单篇】——7.整数反转

题目

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
Given a 32-bit signed integer, reverse digits of an integer.
示例 1:
输入:123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21

个人思路

首先需要说明,中文题目会引起人的误会,32位有符号整数,容易理解成是十进制下的32位;而从英文题目看,32位指的是二进制中的32位,也就是int类型。

方案1:

从目前的观察来看,可以将输入int数字转换成字符串后直接反向输出,需要考虑的是以下几个特例:

  1. 负数:负数的符号需要特殊处理
  2. 末尾为0的情况:末尾为0的数字倒序输出时在开头,不需要输出(使用Java自带的函数这点可以不考虑)
  3. 尤其需要注意的是,翻转越界的问题:如果输入为1534236469,翻转后为9646324351,会超出int的取值范围[-2,147,483,648, 2,147,483,647],这时Java会抛出异常,我们只要捕获这个异常,并且在有异常时返回0即可。

下面是实现代码:

class Solution {
    public int reverse(int x) {
        String xstr = String.valueOf(x);
        String nstr = new String();
        for (int i = xstr.length(); i > 0; i--){
            if("-".charAt(0)==xstr.charAt(i-1)){
                nstr = xstr.charAt(i-1) + nstr;
            } else{
                nstr = nstr + xstr.charAt(i-1);
            }
        }
        int result = 0;
        try{
            result = Integer.parseInt(nstr);
        } catch (Exception e){

        }
        return result;
    }
}

运行结果:

执行用时 :19 ms, 在所有 Java 提交中击败了5.52%的用户
内存消耗 :38.3 MB, 在所有 Java 提交中击败了5.33%的用户

目前来看,这个方法想着比较简单,但实现起来代码还是挺多的,而且事实上速度较慢,占用内存也较多,放在这里,希望能有抛砖引玉的作用。

方案2:

前面想要投机取巧似乎不是个好的方案,那还有一个方案就是通过取余,取出每一位的值,如果而后再计算组合成翻转后的数字。
详细可以参考讨论区中的这个解释,图片解释得很清楚。
很容易可以写出如下的代码:

class Solution {
    public int reverse(int x) {
        int result = 0;
        while(x != 0){
            result = result * 10 + x % 10;
            x = x / 10;
        }
        return result;
    }
}

其实这个题目一个小小的难点是如何控制越界;首先,要复习下,Java中int的最大最小值存储在Integer.MAX_VALUE和Integer.MIN_VALUE中;其次,在计算result的过程中,如果result值越界,不会有任何异常抛出,因此必须在计算前对越界这个情况进行检查。
如果我们记最大值为$maxValue$,最小值为$minValue$,计算前result的值为$r$,x的末尾为$xTail$,那么有:
$r*10+xTail$r*10+xTail>minValue$
继而:
$r < (maxValue - xTail) / 10$
$r > (minValue - xTail) / 10$
如果我们把右边拆开,则有:
$r < maxValue / 10 - xTail / 10$
$r > minValue / 10 - xTail / 10$
这样不就OK了吗,于是有了下面的代码:

class Solution {
    public int reverse(int x) {
        int result = 0;
        while(x!=0){
            if(result > (Integer.MAX_VALUE-x%10)/10)
                return 0;
            if(result < (Integer.MIN_VALUE-x%10)/10)
                return 0;
            result = result * 10 + x % 10;
            x = x / 10;
        }
        return result;
    }
}

这样仍旧会wrong answer。这里值得注意的是,如果x为负数,那么while循环中第一个条件计算结果会溢出;而如果x为正数,那么第二个条件计算结果会溢出;所以不论什么值,都会返回0,修改后:

class Solution {
    public int reverse(int x) {
        int result = 0;
        while(x!=0){
            if(x > 0 && result > (Integer.MAX_VALUE-x%10)/10)
                return 0;
            if(x < 0 && result < (Integer.MIN_VALUE-x%10)/10)
                return 0;
            result = result * 10 + x % 10;
            x = x / 10;
        }
        return result;
    }
}

运行结果:

执行用时 :1 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗 :36.8 MB, 在所有 Java 提交中击败了5.33%的用户

官方解法

详见链接

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;
    }
}

不太一样的地方在于对溢出边界的控制,按照我们前面的记法,
$r*10+xTail$r*10+xTail>minValue$
那么:
$r\geq maxValue/10$
$r\leq minValue/10$
对于$r\geq maxValue/10$,我们有:
$r = maxValue/10$时,如果$xTail > 7$,则计算结果溢出;
$r > maxValue/10$时,计算结果溢出。
同理对于$r\leq minValue/10$,也有:
$r = minValue/10$时,如果$xTail < -8$,则计算结果溢出;
$r < minValue/10$时,计算结果溢出。
于是有了上面的代码。

你可能感兴趣的:(java,leetcode)