题目描述(题目难度,简单)
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 。请根据这个假设,如果反转后整数溢出那么就返回 0。
示例代码
class Solution {
public int reverse(int x) {
long y = x;
long res = 0;
do{
res = 10*res + y % 10;
}while((y /= 10) != 0);
if(res < Integer.MIN_VALUE || res > Integer.MAX_VALUE){
return 0;
}
return (int)res;
}
}
思路解析
这个题的题目难度虽然被划为简单,但是这一题提交的正确率却是前 7 题里最低的。
所以我们不能小看它,这个题我原来在一次机试考试中也遇到过,也顺利的解决了。所以最开始我也看轻了这道题,提交好几次都没通过。问题就出在这个题加了可能溢出这个条件,开始我还想有没有比较巧妙的办法,提前判断反转后会不会溢出,想了几个方法,但提交发现都有漏洞。最后突然想到,这个溢出这么难判断的原因就是使用 int 去存反转后的结果,如果溢出就会把溢出部分的数据位丢掉,导致结果不正确。那我们用一个更长的数据类型(long)去存反转后的结果不就行了,这样肯定不会存在有丢掉数据位的情况。最后直接把反转后的结果与 int 类型的上下限比较即可判断是否溢出。
感觉这是最简洁的办法了,也好记。以后面试遇到就这样回答了(^0^)。
帮大家回忆一下 Java 基本数据类型的长度:
类型 | 长度(字节) |
---|---|
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
float | 4 |
double | 8 |
char | 2 |
还有一点需要注意的就是,Java 数值类型中没有无符号类型
下面也贴出 leetcode 官方给的题解吧,应该算是标准的正解,但饶了点弯,不如上面的代码简洁好记,给大家对比一下,同时给大家多一个思路。
leetcode 官方题解(内容原样复制)
方法:弹出和推入数字 & 溢出前进行检查
思路
我们可以一次构建反转整数的一位数字。在这样做的时候,我们可以预先检查向原整数附加另一位数字是否会导致溢出。
算法
反转整数的方法可以与反转字符串进行类比。
我们想重复“弹出” 的最后一位数字,并将它“推入”到 的后面。最后, 将与 相反。
要在没有辅助堆栈 / 数组的帮助下 “弹出” 和 “推入” 数字,我们可以使用数学方法。
//pop operation:
pop = x % 10;
x /= 10;
//push operation:
temp = rev * 10 + pop;
rev = temp;
但是,这种方法很危险,因为当 时会导致溢出。
幸运的是,事先检查这个语句是否会导致溢出很容易。
为了便于解释,我们假设 是正数。
- 如果 导致溢出,那么一定有
- 如果 ,那么 一定会溢出。
- 如果 ,那么只要 ,就会溢出。
当 为负时可以应用类似的逻辑。
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;
}
}
怎么样,对比后,是不是发现还是第一种方法更简单更好理解一点呢(嘻嘻)。
补充两点知识点*(也挺重要)
一、取余运算和取模运算的异同
这个题目最开始,我还是分正负数来考虑的,因为我印象里记得 %
对正数和负数的运算好像有区别。最后去查了一下,补充在这里。
C/C++ 和 Java 一样,% 是取余运算;而 Python 的 % 是取模运算。
取余运算和取模运算的区别:
对于整型数 来说,取余运算或者取模运算的方法都是下面两步:
- 求整数商:
- 计算余数或者模:
而两者的区别就在于第一步不同:取余运算在取的值时,向 方向舍入,而取模运算在计算的值时,则是向负无穷方向舍入。
例如计算:
第一步:求整数商,取余运算算出的整数商为,而取模运算算出的整数商为
第二步:计算余数和模的公式相同,但因的值不同,取余的结果为,取模的结果为。
归纳:当和符号一致时,取余运算和取模运算的结果一样。
当符号不一致时,结果不一样。取余运算结果的符号和一致,取模运算结果的符号和一致。
验证结果如下:
对于 Java 来说,
代码如下:
public class Test {
public static void main(String[] argus){
System.out.println("-7 % 4 = "+(-7%4));
System.out.println("7 % -4 = "+(7%-4));
}
}
运行结果如下:
image.png
对于 Python 来说,
image.png
参考链接:
https://baike.baidu.com/item/%E5%8F%96%E6%A8%A1%E8%BF%90%E7%AE%97/10739384?fr=aladdin
二、Java 位运算部分知识点
在解这道题的时候,考虑过使用位运算简化代码。虽然最后没用上,但还是记在这吧,万一以后用的上呢。
一、Java 移位运算
<<
为左移运算,>>
为右移运算(左边补符号位),>>>
为无符号右移运算(左边恒补 0),注意 Java 中没有<<<
运算符。
二、Java 取绝对值的位运算实现
int abs(int x){
return (x+(x = x>>31))^x;//有点过于精炼,哈哈
}
分解一下代码,实际上是有两步,
第一步,令 y = x >> 31
第二步,返回结果 (x+y) ^ y
代码解释如下:
- 当
x
为正数时,y = 0
,则(x+0) ^ 0
还是x
。 - 当
x
为负数时,x
右移 31位,左边补符号位 1 ,最终y = 0xFFFFFFFF
,也即y = -1
。所以(x+y) ^ y = (x-1)^0xFFFFFFFF = ~(x-1) = -x
,perfect!!!
完结撒花
网友评论