7.反转数字-处理溢出的条件-Java
题目:反转数字
描述
给定一个32位的有符号整数num,将num中的数字部分反转,最后返回反转的结果。
1.只反转数字部分,符号位部分不反转。
2.反转后整数num超过 32 位的有符号整数的范围$[-2^{31} ,2^{31}-1] $ ,返回 0。
3.假设本题不允许存储 64 位整数(有符号或无符号,即C++不能使用long long ,Java不能使用long等)。
数据范围:
$ -2^{31} <= x <= 2^{31}-1 $
错误处理溢出代码
if(x>=(2<<32-1)) return 0;
if(x<=-(2<<32)) return 0;//int类型根本无法表示。。。神
正确处理溢出代码
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && digit > 7)) {
return 0;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && digit < -8)) {
return 0;
}
原理
在执行可能导致溢出的操作前,用反向运算判断是否会溢出,避免直接计算溢出值。以 res = res * k + digit 为例(k 是倍数,如 10、3 等),步骤如下:
确定目标范围:比如 int 的范围是 [min, max](min = -2147483648,max = 2147483647)。
拆分操作:要执行 res * k + digit,先判断 res * k 是否会溢出,再判断加 digit 后是否溢出。
反向判断:
若 k > 0:
- 正数溢出:res > max / k → 此时 res * k 必超 max;
若 res == max / k,则需额外判断 digit > max % k(超出余数则溢出)。 - 负数溢出:res < min / k → 此时 res * k 必小于 min;
若 res == min / k,则需额外判断 digit < min % k(超出余数则溢出)。
坑
Math.abs(Integer.MIN_VALUE);
输出仍为Integer.MIN_VALUE。
完整代码
public int reverse(int x) {
int res = 0;
while (x != 0) {
int digit = x % 10;
x = x / 10;
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && digit > 7)) {
return 0;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && digit < -8)) {
return 0;
}
res = res * 10 + digit;
}
return res;
}
错误代码
public int reverse (int x) {
boolean sign=false;
if(x>=(2<<32-1)) return 0;
if(x<=-(2<<32)) return 0;//int类型根本无法表示。。。神
if(x>=0) sign=true;
if(!sign) x=Math.abs(x);//Math.abs有坑
int res=0;
while(x>0){
res=res*10+x%10;//具有溢出的风险 res每次都扩大10倍并且加上一个0-9的数
x=x/10;
}
return sign?res:-res;//有关符号判断根本不用判断,修改while条件为!=10。
//用除法和取余的反向运算,在实际计算前拦截溢出,这是处理整数溢出的标准解法。
}
浙公网安备 33010602011771号