这是来自力扣的第7道算法题,题目是:
这道题是一道简单题,但是我不会做,绞尽脑汁没有想出来(我承认自己菜鸡)。
先来看一下题目,是一个32位的有符号整数,在计算机中,8位是一个字节,32位就是4字节。而在Java中,4字节的整数就是int类型,而题目要求不允许存储64位的整数,那么意思就是这道题中不让使用long类型。
继续看题,如果反转后超过int类型的范围,就返回0。这里思考一下为什么会超出这个范围呢?比如说给出的整数为-2的31次方,它反转后的结果就是2的31次方,而int最大的范围是2的31次方-1,会超出取值范围,所以如果最终得到的结果是2的31次方,直接返回0。
然后看示例,示例1很正常没啥可说的。而示例2,给出的数字是-123,而需要输出的数字是-321,这就说明翻转的时候要保留符号。示例3给出的是120,结果是21,这代表着反转后需要把0给去掉。
看到这里,我的脑海里首先想的是被这个数字变成字符串,判断索引值为0的字符(也就是第一位)是否为负号,如果是的话保留这个符号。然后再把末尾的0删掉,最后进行数组翻转,再转换为数字。可是这样操作的成本好像有点高,代码量也多,不想用也不想写(该题评论区有此解法,可以去看下)。
有没有简单写法?有。
首先,我们可以先定义一个boolean类型的变量,用来判断该数是正数还是负数。如果是负数,该变量的值为true,正数则是false,然后取该数的相反数。
class Solution {
public int reverse(int x) {
// 定义一个用于判断x是正数还是负数的变量
boolean flag = false;
// 如果x为正数,则flag值不变,如果为负数,则取x的相反数,并将flag设置为true
if(x < 0) {
x = -x;
flag = true;
}
}
}
不过这里插一下,如果x是int类型的最小值,那么他的相反数则是等于int类型的最大值加1,int类型的最大值加1等于int类型的最小值,所以....x还是等于它本身。下图是使用debug测试的结果。
既然要把反转的数字返回,x还需要用,则需要再定义一个变量,用于接收最终的结果。
int res = 0;
重头戏来了,如何反转??!!
如果x等于0,直接返回即可,没必要进行反转。如果等于0的话,再进行反转。
反转可以进行取模运算。
x % 10 得到的结果就是x的个位数,把这个结果赋值给res,这样就反转了第一位数。
取到第一位数之后,第一位数就没用了,可以将x除以10。因为x是int类型的,除以10之后得到的个位数就是之前的十位数,之前的个位数就被丢掉了(好惨)。
此时可以得到代码:
res = x % 10; x /= 10;
此时的第二位数就是现在x的个位数,再将 x % 10 就能得到,而现在的res的值是刚刚的个位数,将 res * 10 再加上现在得到的第二位数,就是反转后的数。
这里可以得到代码:
res = res * 10 + x % 10; x /= 10;
其它位数以此类推。
找到规律,上循环:
while(x != 0){
// 每循环一次 res的值*10,再加上x%10后的值
// 比如 123 取模后的值是3 第一次循环0*10+3=3 第二次循环3*10+2
// 第三次循环 32*10+1 此时结果就是321了
res = res * 10 + x % 10;
x /= 10;
}
还记得刚刚的flag吗,如果初始的x是正数,直接返回,如果是负数,取反后返回。
return flag ? -res : res;
别急,还没有结束,如果x的初始值是int类型的最小数,怎么办?这样写得到的结果肯定是不对的,所以要做处理。
打开JDK API的Integer类,在java.lang包中,可以看到有一个常量MAX_VALUE,这个常量表示了int类型的最大值。
刚刚讲了,当 x % 10 的时候可以得到x的个位数。x是经过我们取反的,如果是int的最小值,x % 10 的结果还是个负数,Integer.MAX_VALUE减去这个个位数,减去这个负数,就相当于加上了这个数的相反数,当int类型越界了之后就还是负数。
由此可以得到代码:
if(0 > (Integer.MAX_VALUE - x % 10)) {
return 0;
}
问题没有那么简单,如果取反操作(x = -x)后和int类型的最大值位数一样,但是x的最高位大于int类型的最大值的最低位,那么反转后也会溢出。解决方法就是将我们刚刚的判断写到循环中,并且再加上点东西:
if(res > (Integer.MAX_VALUE - x % 10) / 10) {
return 0;
}
最终代码为:
class Solution {
public int reverse(int x) {
boolean flag = false;
if(x < 0) {
x = -x;
flag = true;
}
int res = 0;
while(x != 0){
if(res > (Integer.MAX_VALUE - x % 10) / 10) {
return 0;
}
res = res * 10 + x % 10;
x /= 10;
}
return flag ? -res : res;
}
}
此时举例说明:
假设x最开始的值是1534236469
第一次循环:res是0,(Integer.MAX_VALUE - x % 10) / 10 的值是214748363
以此类推,关注最后一次循环
最后一次循环开始之前 x 的值为 1, res 的值为964632435
x % 10 = 1 % 10 = 1
Integer.MAX_VALUE - 1 = 2147483646
2147483646 / 10 = 214748364
如果此时 res 是大于这个值的话,那说明该数字反转后是会溢出的,因为res还需要再进行一次*10的操作,不管加不加最后的只有一位数的x的值都是溢出的
所以直接返回0
怎么样?你看懂了吗?
在力扣上提交代码后得到如下结果
该题虽然是简单题,但我觉得好难。没有做出来的小伙伴也不要气馁(我也没做出来),大家多做多练多看看题解,才能提高自己。
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-integer/
题目著作权归领扣网络所有



