思路
这道题和上一道题有点类似, 基本实现很容易, 主要难度在于corner case的考虑...
实现
我的实现过程中考虑了如下几种情况的corner case :
- 输出为空字符串 --> 返回0.
- 输出中带有小数或者其他非法字母(eg : 3.12) --> 在出现的非法字母的地方停止.
- 输出越界, 超过最大或者最小整数 --> 正数返回最大整数, 负数返回最小整数.
提交
不幸的是仍然错了3次, 主要漏掉了这两种corner case :
- 字符串前面带一串空格.
- 字符串前面带正号(一般都会想到字符串前面要么带负号要么不带, 这里带正号的情况很难想到)
同时我还考虑错了一种情况 : 就是在如何判断数据越界的问题上, 我采用了上一题中使用的那种回算的方式, 但是我发现那个想法其实是有问题的, 比如 x 经过 x * 10 + y 的结果是z, 那么如果z越界 (z - y) / 10 == x有可能为真, 也有可能为假, 这个不是绝对的. 例如可以考虑x = 214748364 * 10, y = 9的情况, 这时候 x * 10 + y的值显然溢出了, 但是前面那个等式确实是成立的. 那么到底什么情况下为真什么情况下为假呢?
- 如果是后面的加法导致的越界, 那么为真, 因为加法就算越界也保持可逆性.
- 如果是前面的乘法就已经越界, 那么为假.
所以第7题之所以可以那么判断, 是因为它输入的也是一个int, 要想出现加法越界, 除非最后一位是大于7, 也就是输入int的第一位就大于7, 这样的话输入的int已经越界了, 所以不可能出现加法越界的情况, 所以要特别小心.
代码
public class Solution {
public int myAtoi(String str) {
str = str.trim();
boolean isNegative = false;
boolean isOverflow = false;
long re = 0;
for(int i = 0; i < str.length(); ++i){
if(i == 0 && (str.charAt(i) == '-' || str.charAt(i) == '+')){
isNegative = str.charAt(i) == '-';
continue;
}
if(Character.isDigit(str.charAt(i))){
re = re * 10 + str.charAt(i) - '0';
if(re < 0x80000000l) continue;
else isOverflow = true;
}
break;
}
if(isNegative){
return isOverflow ? 0x80000000 : -(int)re;
}
else{
return isOverflow ? 0x7fffffff : (int)re;
}
}
}
最佳实现
对于我的解法的改进, 网上主要集中在不使用long, 而是判断Integer.MAX_VALUE/10 < total || Integer.MAX_VALUE/10 == total && Integer.MAX_VALUE %10 < digit
(total 是当前的re, digit 是当前i指向的字符), 通过在计算之前判断是否会溢出即可. 比较简单, 所以这里就不贴具体代码了.