题目:
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:输入: -123
输出: -321
示例 3:输入: 120
输出: 21
注意:假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-integer
思路:
这个题非常简单,主要的点就是注意溢出,以及代码实现的流畅度。
做题过程:(这个过程有问题,最后反思部分解释)
首先,如果要做反转,那么就是对数字部分进行反转,最后加上符号。
那么这个时候就可以知道代码的开头需要获取符号,最后根据符号返回正数或者负数。结构如下:
class Solution {
public int reverse(int x) {
int flag = x >= 0 ? 1 : -1;
int result = 0;
// do calculation
return result * flag;
}
}
然后中间部分就是对原始数字从个位开始遍历,反转记录到result中。这个过程中需要注意反转后不能溢出。这时候首先是对原来的数据求绝对值,那么求绝对值首先也注意不能溢出,而在x为Integer.MAX_VALUE的时候直接取其绝对值是会溢出的,所以需要做一个特殊判断。代码如下:
class Solution {
public int reverse(int x) {
if (x == Integer.MIN_VALUE) {
return 0;
}
int flag = x >= 0 ? 1 : -1;
int result = 0;
// do calculation
return result * flag;
}
}
最后就是遍历了,同时判断是否越界。代码如下:
class Solution {
public int reverse(int x) {
if (x == Integer.MIN_VALUE) {
return 0;
}
int flag = x >= 0 ? 1 : -1;
int result = 0;
for (int origin = Math.abs(x); origin > 0; origin /= 10) {
int yushu = origin % 10;
if (result > Integer.MAX_VALUE / 10) {
return 0;
}
result = result * 10 + yushu;
}
return result * flag;
}
}
判断是否越界的方法就是:当前的result没有超过Integer.MAX_VALUE的高位,只要能达到这个条件,再增加一位也不会越界。但是这个条件是完全足够的吗?其实是的,因为如果result==Integer.MAX_VALUE/10,然后新增的一位导致其越界,那么新增的一位应该是大于7的,而这一位在原始数据中处于最高位,和Integer.MAX_VALUE同位数且最高位大于7一定越界了,所以这样的x不存在。这个其实利用了一些限制条件做了推测。
反思:
上面的这个解题结果是对的,但是解题过程还是有点问题。其实有一个越界可能性并没有在解题的一开始进行考虑,只不过在最后能cover住而已。
一开始直接就认为可以把符号取出来,中间过程用绝对值去进行计算,最后根据符号位和基于绝对值计算出来的结果组合出返回值。这个思路其实是有问题的,用绝对值去进行计算,是认为正负数是可以完全统一的,但是并没有进行严格的论证。
虽然在第二步考虑了输入中负数和正数的不同,对负数最小值进行了单独处理。但是没有对结果的负数范围进行考虑。结果的负数范围是可能取到Integer.MIN_VALUE的,而这个如果用绝对值去进行计算是会越界的。这个只是发现不可能存在这样的数字,但是在一开始就直接把正负数取绝对值统一计算过程的编码方式还是不妥当的。
官方代码如下,从逻辑上更严谨和简练:
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;
}
}
耗时:
46分钟。虽然简单,但是还是有很多的点没想到,花费的时间比预期长。