原因
我注意到LeetCode中有一道中等难度的题——《整数反转》通过率很低,但是我看完题目觉得挺简单的,想着提高一下它的通过率,然后就随手写了段代码,测试都通过了,提交时却报错。
代码:
class Solution {
public int reverse(int x) {
int result = 0;
boolean flag = true;
if (x < 0) {
x = -x;
flag = !flag;
}
while(x > 0){
int currentDigit = x % 10;
result = result * 10 + currentDigit;
x = x / 10;
}
result = flag ? result : -result;
if (result >= Integer.MIN_VALUE && result <= Integer.MAX_VALUE) {
return result;
} else {
return 0;
}
}
}
提交的时候报错:
我一看结果就知道我没有考虑到整数类型的溢出问题,难怪这道题的通过率这么低。
int类型的范围
Java中int
类型的值的范围是从 -2^31
到 2^31 - 1
,具体数值是:
- 最小值:
-2,147,483,648
- 最大值:
2,147,483,647
这个范围是由int
类型占用的内存大小决定的。在Java中,int
类型占用4个字节(即32位),其中最高位表示符号位(0代表正数,1代表负数),剩余31位用于存储数值部分。由于这种二进制表示方式,所以它可以表示的最大正整数是2的31次方减1,而最小负整数则是-2的31次方。
Java中基本数据类型的范围
为了以防下次我再忽视这种问题,我将java中基本数据类型的范围都罗列了一遍。
Java中的基本数据类型包括整数型、浮点型、字符型和布尔型,其范围如下:
-
整数型:
byte
: 占用1个字节(8位),有符号整数,范围从-128
到127
。short
: 占用2个字节(16位),有符号整数,范围从-32,768
到32,767
。int
: 占用4个字节(32位),有符号整数,范围从-2,147,483,648
到2,147,483,647
。long
: 占用8个字节(64位),有符号整数,范围从-9,223,372,036,854,775,808
到9,223,372,036,854,775,807
。
-
浮点型:
float
: 占用4个字节(32位),单精度浮点数,根据IEEE 754标准,能表示非常大的正负数值以及很小的近似值,但不精确。double
: 占用8个字节(64位),双精度浮点数,同样遵循IEEE 754标准,具有更大的精度和更大的数值范围。
-
字符型:
char
: 占用2个字节(16位),无符号整数,用来表示Unicode字符,范围从U+0000
到U+FFFF
(即0
到65535
)。
-
布尔型:
boolean
: 表示逻辑值,不直接对应特定的内存大小。在Java中,只包含两个可能的值:true
和false
。
范围溢出方法的解决方案
我通过搜寻资料总结了一些范围溢出的解决方案
-
选择合适的数据类型:
如果在处理整数时出现溢出,可以考虑使用更大范围的整数类型。例如在Java中,如果int
类型不足以容纳计算结果,可以尝试改用long
或BigInteger
(无符号大整数类)。 -
检查并限制输入值:
在程序接收输入或者进行操作前,先检查数值是否在允许范围内,避免直接进行可能导致溢出的操作。 -
模块化运算:
对于某些特定场景,如计数、循环等,可以采用模运算来确保数值始终在某个范围内。 -
使用库函数或语言特性:
许多编程语言提供了检测溢出的功能,例如Java中的Math.addExact()
,Math.multiplyExact()
等方法可以在执行操作时检查是否发生溢出,并在发生溢出时抛出异常。 -
位运算:
对于一些特殊的计算需求,比如二进制位操作,可以通过理解并利用位运算的特点来进行安全的计算,避免溢出。 -
使用浮点数代替整数:
在一定精度要求下,对于非常大的数值,可以考虑使用浮点数类型,但需要注意的是浮点数并不能精确表示所有整数,且有其自身的精度限制和误差问题。 -
分治算法:
对于大型计算任务,可以采用分治策略将大问题分解为小问题分别处理,每一步都确保不发生溢出。 -
使用无符号类型:
部分编程语言支持无符号整数类型,它们可以提供更大的正数范围,但在处理负数时需要额外注意。
整数反转的代码修正
class Solution {
public int reverse(int x) {
Long result = 0L; //将result改成Long类型,则不会出现int类型的溢出问题
boolean flag = true;
if (x < 0) {
x = -x;
flag = !flag;
}
while(x > 0){
int currentDigit = x % 10;
result = result * 10 + currentDigit;
x = x / 10;
}
result = flag ? result : -result;
if (result >= Integer.MIN_VALUE && result <= Integer.MAX_VALUE) {
return result.intValue(); //因为函数是int类型的,所以需要将Long类型先转成int类型
} else {
return 0;
}
}
}
只需要将代码中的result改成Long类型,因此在while循环的过程中就不会出现int类型溢出的问题,最后再返回的过程中再将result类型转换成int类型。