【刷题】整数反转(ReverseInteger)

部门通知又要开始考试了,于是就又要开始刷题了,从今天起,争取在leetcode上刷一道题,目标是不要定的太高,工作日做简单的,周六日做困难的。加油,没事刷些题也是好的,工作用不着,面试还能用呢~就像口罩没想到自己能成为热门年货,未来的事儿谁说的准呢。

题目

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例 1:

输入: 123
输出: 321

示例 2:

输入: -123
输出: -321

示例 3:

输入: 120
输出: 21

注意:

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [231,2311]。请根据这个假设,如果反转后整数溢出那么就返回 0。

来源:https://leetcode-cn.com/problems/reverse-integer

解题

思路

这个题目很简单,看到的第一个想法就是输入改成字符串,然后用charAt反着遍历一遍。

看到示例二,想起还有负数,在反着读的时候还要考虑一下首位的问题,这么一来,特殊处理有点麻烦,所以想着只用字符串来表示他的数字部分,符号单拿出来最后添上。

注意中提到要是反转后溢出需要返回值为0,那肯定要用long来缓存这个数,让他随便折腾,最后再和Integer.MAX_VALUEInteger.MIN_VALUE比较一下输出就好了。

于是有了第一版代码

代码
public int reverse(int x) {
    boolean isNegative = false;
    long temp = x;
    if (x < 0) {
        isNegative = true;
        temp = -x;
    }
    String str = String.valueOf(temp);
    StringBuilder sb = new StringBuilder();
    for (int i = str.length() - 1; i >= 0; i--) {
        sb.append(str.charAt(i));
    }
    temp = isNegative ? -Long.valueOf(sb.toString()) : Long.valueOf(sb.toString());

    if (temp > Integer.MAX_VALUE || temp < Integer.MIN_VALUE) {
        return 0;
    }
    return (int) temp;
}

感觉很完美,于是submit了一把,然后啪啪打脸,Line 14: java.lang.NumberFormatException: For input string: "8463847412-"
仔细查一遍代码,在输入值为负数时,我直接用temp=-x进行赋值,一般场景没有问题,但是在Integer的下边界时出现了问题,Integer.MIN_VALUE的数字部分比Integer.MAX_VALUE要大一,直接取负会先按照int进行变换,溢出,再扩大范围赋值给temp,改成temp = -temp后全用例通过。

ps: 我的解法很暴力,浪费了不少空间,只比29%的同学强,有更加节约的方法可以处理这个问题。
看了下leetcode上的正统答案,是纯靠数学思路解决问题的。操作也不难,就是边界设计确实是我没想的到的。具体实现思路如下,将input每次对10求余,然后将余数乘10叠加,就相当于时10进制的左移以为,但是需要考虑溢出问题,然后居然还用到了放大缩小!!!所以有了下面的推导。

int remainder = x % 10;
x = x/10;
int ans = ans * 10 + remainder;

左侧ans最大为IntegerMax,所以上一次剩余的ans最大只能为IntegerMax/10,其实也好理解,就是最大int值长度,最后一位是0,即ans<IntegerMax/10时,随便处理当ans=IntegerMax/10时,就要考虑后面的remainder其最大值为IntegerMax-IntegerMax/10*10=7.
所以有如下代码:

public int reverse(int x) {
    int ans = 0;
    while (x != 0) {
        int remainder = x % 10;
        x /= 10;
        if (ans > Integer.MAX_VALUE/10 || (ans == Integer.MAX_VALUE / 10 && remainder > 7)) return 0;
        if (ans < Integer.MIN_VALUE/10 || (ans == Integer.MIN_VALUE / 10 && remainder < -8)) return 0;
        ans = ans * 10 + remainder;
    }
    return ans;
}
知识点
  1. StringBuilder是非线程安全的,StringBuffer是线程安全的,用StringBuilder是因为他做拼接时效率比较高。
  2. 在做符号操作时,不会进行范围扩展,窄范围向宽范围进行转换时,可直接赋值过去,反之因为会发生精度丢失,需要声明强转。(Java编程思想简要笔记——第三章 操作符
  3. 负数求余怎么做?
    a = q d + r 且 0 ≤ r < d a = qd + r 且0 ≤ r < d a=qd+r0r<d 其中 q q q是商, r r r是余数, d d d是除数。所以对于 − 1 ÷ 10 -1÷10 1÷10就可以很快得出 − 1 = − 1 ∗ 10 + 9 -1=-1*10+9 1=110+9这个和-1%10的结果是不一样的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kiba_zwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值