题目:String to Integer (atoi)
Implement atoi to convert a string to an integer.
分析:转换输入字符串为数字,原以为这是一道巨水题,单次提交通过肯定是没问题了,哪知......
题目要求:
- 如果前面有空格开头,忽略掉开头的所有空格
- 如果发现没意义的字符,忽略之,并结束转换。即
123ttyw
->123
- 考虑负数额
- 如果溢出,则返回相应的最大正数和最大负数。
考虑完这些问题后,我便傻哈拉地敲起了代码,敲完瞅了瞅觉得天衣无缝,我就是编译器一切尽在掌握的姿态有木有。
public class Solution {
public int atoi(String str) {
if (str.length() == 0) return 0;
boolean positive = true;
int len = str.length();
int i = 0;
// discard whitespace
while (i < len && str.charAt(i) == ' ') {
i++;
}
if (i < len && str.charAt(i) == '-') {
positive = false;
i++;
}
if (i < len && str.charAt(i) == '+') {
i++;
}
int t = 0, num = 0;
for (; i < len; i++) {
t = str.charAt(i) - '0';
if (t < 0 || t > 9) break;
num = num*10 + t;
if (num < 0) break;//already overflow..
}
// overflowed
if (num < 0) {
return positive ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
return positive ? num : -num;
}
}
运行时出现了一个巨诡异的错误:
Input: " 10522545459"
Output: 1932610867
Expected: 2147483647
10522545459已经溢出了32位有符号整型的范围,但是怎么给我得出了1932610867这种诡异的结果。这就要涉及到补码的运算规则了(在《深入理解计算机系统》的第二章2.3.5节提到了补码乘法)。
当程序运行到num为1052254545时,扫到了9,于是便做
1052254545*10 + 9 => 10522545450 + 9
嗯,没错,即便溢出了,计算机也能给我们算出正确值的。坑就坑在计算完了之后,会对多出的位进行截断。
1052254545 * 10 = 10522545450
0x3EB82151 * 0xA = 0x273314D2A (已经超出32位了,截掉多出的最高位2, 得到0x73314D2A
0x73314D2A对应的便是1932610858了,加上9,便得到了1932610867.
结论:切不可认为正数乘法溢出时一定得到负数啊。
所以判断的条件要这么改:
/**
* MAX为最大整数,MIN为最小整数
**/
if (MAX/10 >= num) {
num = num*10 + t;
} else{
return positive ? MAX: MIN;
}
if (num < 0) {
return positive ? MAX: MIN;
}
如果MAX/10 >= num
的话,那么num*10
一定是小于等于MAX
的,再加上t
,分情况讨论:
- 如果
num*10 + t
溢出,由于t < 10,根据补码的加法法则,num*10 + t
一定是负数 - 如果
num*10 + t
得到的是正数,则表明没有溢出,这一定是要求的结果 - 如果要求的数字是负数
- 当
num*10 + t
为正数时,取-(num*10 + t)
即可 - 当
num*10 + t
为负数时,表示已经溢出了正数范围。对于32位的补码而言,取值范围为-2^31 ~ 2^31 - 1,最小负数的绝对值仅比最大正数的绝对大1,故当超出正数范围时,我们直接取最小负数即可。
- 当
最终代码:
public class Solution {
public int atoi(String str) {
if (str.length() == 0) return 0;
boolean positive = true;
int len = str.length();
int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;
int i = 0;
// discard whitespace
while (i < len && str.charAt(i) == ' ') {
i++;
}
if (i < len && str.charAt(i) == '-') {
positive = false;
i++;
}
if (i < len && str.charAt(i) == '+') {
i++;
}
int t = 0, num = 0;
for (; i < len; i++) {
t = str.charAt(i) - '0';
if (t < 0 || t > 9) break;
if (max/10 >= num) {
num = num*10 + t;
} else{
return positive ? max : min;
}
if (num < 0) {
return positive ? max : min;
}
}
return positive ? num : -num;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。