【算法攻坚】整数翻转的小技巧

492 阅读2分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

题目

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

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

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

示例 1:

输入:x = 123 输出:321

示例 2:

输入:x = -123 输出:-321

示例 3:

输入:x = 120 输出:21

示例 4:

输入:x = 0 输出:0

思路

看到这道题目的时候,首先想到的是转换成字符串,然后翻转,所以迅速写完第一版

public int reverse(int x) {
    StringBuffer s = new StringBuffer(String.valueOf(x));
    if(x> 0){
        return Integer.valueOf(s.reverse().toString());
    }else if(x <0){

        return - Integer.valueOf(s.reverse().toString().substring(0,s.length()-1));
    }else{
        return 0;
    }
}

执行出错信息:

java.lang.NumberFormatException: For input string: "9646324351"  at line 68, java.base/java.lang.NumberFormatException.forInputString  at line 658, java.base/java.lang.Integer.parseInt  at line 989, java.base/java.lang.Integer.valueOf  at line 6, Solution.reverse  at line 54, __DriverSolution__.__helper__  at line 84, __Driver__.main

最后执行的输入:

1534236469

这个报错是因为当输入是1534236469,翻转后是9646324351

但是这样再用Integer.valurOf()就会超过int类型的最大值2147483647

如果能够看出问题所在,这时按照题目要求,超出范围后直接返回0

我们就可以利用异常来控制返回,当有异常时直接返回0

public static int reverse(int x) {
    try {
        StringBuffer s = new StringBuffer(String.valueOf(x));
        if (x > 0) {
            return Integer.valueOf(s.reverse().toString());
        } else if (x < 0) {
            return -Integer.valueOf(s.reverse().toString().substring(0, s.length() - 1));
        } else {
            return 0;
        }
    } catch (Exception e) {
        return 0;
    }
}

执行用时:2 ms, 在所有 Java 提交中击败了22.09%的用户

内存消耗:35.7 MB, 在所有 Java 提交中击败了22.48%的用户

从结果看,效率不算太高,可以考虑下其他方法,字符串操作相对比较耗时

解法二

由于字符串操作比较耗时,所以选择数学公式方式实现

依次取出当前数字的最后一位数,累加。

关键在于如何判断整数溢出:

可以每次操作后的数字用临时变量存储,对该变量反向运算,

若与操作前的结果不等,则发生溢出,直接返回0

public int reverse(int x) {
    int result = 0;
    while(x != 0){
        //当前操作位数字
        int cuur = x%10;
        //result*10相当于低位每次右移以为就乘以10,比如123, 3*10, 3*10*10*10+2*10,3*10*10+2*10*10 +1*10
        int temp =  cuur + result*10;
        //上一行运算的逆运算,判断是否超出int范围
        if((temp - cuur)/10 != result){
            return 0;
        }
        x = x/10;
        result = temp;
    }
    return result;
}

执行用时:1 ms, 在所有 Java 提交中击败了97.47%的用户

内存消耗:35.6 MB, 在所有 Java 提交中击败了30.81%的用户

解法三

int类型的数字翻转也不会超过long的范围,所以可以利用long类型和int类型转换后

判断是否相等来验证是否超出int范围

public int reverse(int x) {
    long result = 0;
    while(x != 0){
        int cuur = x%10;
        result = result *10 + cuur;
        x = x/10;
    }
    //如果不超出范围,强转类型后数值不变化
    int res = (int)result;
    return res == result? res: 0;
}

执行用时:1 ms, 在所有 Java 提交中击败了97.47%的用户

内存消耗:35.2 MB, 在所有 Java 提交中击败了94.37%的用户

今天多学一点,明天就少说一句求人的话,加油!