算法通关村—数字溢出问题处理模板

溢出问题是一个极其重要的问题,只要涉及到输出一个数字,都可能遇到,典型的题目有三个:数字反转,将字符串转成数字和回文数。 不过溢出问题一般不会单独考察,甚至面试官都不会提醒你,但他就像捕捉猎物一样盯着你,看你会不会想到有溢出的问题,例如这道题是一个小伙伴面美团时拍的。所以凡是涉及到输出结果为数字的问题,必须当心!

1. 整数反转

LeedCode7
在这里插入图片描述
该题目的关键有两点,一是如何进行数字反转,二是如何判断溢出。
首先想一下,怎么去反转一个整数。用栈?或者把整数变成字符串再反转字符串?都可以但都不好。我们只要一边左移一边处理末尾数字就可以了。以12345为例,先拿到5,再拿到4,之后是3,2,1,然后就可以反向拼接出一个数字了。那如何获得末尾数字呢?好办,循环取模运算即可。例如:

1.将12345 % 10 得到5,之后将12345 / 10=1234
2.将1234 % 10 得到4,再将1234 / 10=123
3.将123 % 10 得到3,再将123 / 10=12
4.将12 % 10 得到2,再将12 / 10=1
5.将1 % 10 得到1,再将1 / 10=0

在这里插入图片描述
这样的话,是不是将循环的判断条件设为x>0就可以了呢?不行!因为忽略了负数的问题,应该是while(x!=0)。去掉符号,剩下的数字,无论正数还是负数,按照上面不断的/10这样的操作,最后都会变成0,所以判断终止条件就是!=0。有了取模和除法操作,就可以轻松解决第一个问题,如何反转。
接下来看如何解决溢出的问题。我们知道32位最大整数是MAX=2147483647,如果一个整数num>MAX,那么应该有以下规律:
nums/10 > MAX/10=214748364,也就是如果底数第二位大于4了,不管最后一位是什么都已经溢出了,如下:
在这里插入图片描述
所以我们要从到最大数的1/10时,就要开始判断,也即:

  • 如果 num>214748364 那后面就不用再判断了,肯定溢出了。
  • 如果num= 214748364,这对应到上图中第三、第四、第五排的数字,需要要跟最大数的末尾数字比较,如果这个数字比7还大,说明溢出了。
  • 如果num<214748364,则没问题,继续处理。
    这个结论对于负数也是一样的,所以实现代码就是:
public static int reverse(int x) {
        int res = 0;
        while (x != 0) {
            int num = x % 10;
            x /= 10;
            if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && num > (Integer.MAX_VALUE % 10))) {
                return 0;
            }
            if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && num < -(Integer.MIN_VALUE % 10))){
                return 0;
            }
            res = res * 10 + num;
        }
        return res;
    }

2. 字符串转整形

LeedCode8意思就是字符串转整数(atoi函数),题目比较长,解决过程中要涉及很多异常情况的处理,我在《不简单的字符串转换问题》一节进行了详细讲解,有需要的同学请回顾一下相关的内容。

3. 回文数

LeedCode9
在这里插入图片描述
思路解析:

  • 映入脑海的第一个想法是将数字转换为字符串,并检查字符串是否为回文。但是,这需要额外的非常量空间来创建问题描述中所不允许的字符串。
  • 第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。 但是,如果反转后的数字大于int.MAX,我们将遇到整数溢出问题。
  • 按照第二个想法,为了避免数字反转可能导致的溢出问题,为什么不考虑只反转 int 数字的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。
    例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。
    这个反转思路与链表的反转是一样的,不过要简单多了。
    这里还不能忘的问题就是,反转之后数字可能会溢出,因此必须做防范,方法我们上面说了,这里我们可以进一步简化一下:
public static boolean isPalindrome3(int x){
        //当 x 小于0,或者 x的尾数为0但是自身不为0,则不可能为 回文数
        if(x < 0 || (x % 10 == 0 && x != 0)){
            return false;
        }
        int ans = 0;
        while (ans < x){
            ans = ans * 10 + x % 10;
            x /= 10;
        }
        return ans == x || ans / 10 == x;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值