题目描述
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
- 本题中的空白字符只包括空格字符 ’ ’ 。
- 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31, 2^31 − 1]。如果数值超过这个范围,请返回 INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。
思路分析
题目很清晰地给出了转化规则,我们需要将其转化为代码。
- trim() 将字符串首部的空格去除;
- 判断第一个字符:
- 为 ‘-’ 则将标志位置为 -1 ,从第二位开始算;
- 为 ‘+’ 则将标志位置为 1 ,从第二位开始算;
- 为除数字 0-9 外的字符直接返回。
- 主要问题在 int 的边界问题上。
- 最小负数
- int的最大正数的绝对值小于最小负数绝对值。我们需要让符号位也参与运算过程,避免最后置负时超出边界。’+’ => 1;’-’=> -1。
- 数值越界
- 在每次循环时,通过INT_MAX/10的值提前判断是否越界。
- value > INT_MAX/10 时,说明扩大10倍后,value 必将越界。
- 当 value == INT_MAX/10 时,说明扩大10倍后,value 可能越界,也可能不越界,需要利用当前的加数 digit 做进一步的判断:正数是当 digit > 7 时,越界;复数是当 digit > 8 时,越界。
- 当 value < INT_MAX/10 时,本轮循环必不越界。
- 正负数越界判断合并
- 将-1、1转换为0、1 => (isNegative + 1) / 2 + digit > 8时,数值越界。
- 最小负数
综上所述,
overValue = isNegative * value - INT_MAX/10
+ (((isNegative+1)/2 + digit > 8) ? 1:0);
当overValue>0时,数值将会越界,反之不会。
代码实现
public static int myAtoi(String str) {
if(str==null||str.length()==0){
return 0;
}
str = str.trim();
if(str==null||str.length()==0){
return 0;
}
int isSub = 1;
int sum = 0,overvalue = 0,digit = 0,index = 0;
if (str.charAt(0) == '-') {
isSub = -1;
index = 1;
} else if (str.charAt(0) == '+') {
isSub = 1;
index = 1;
} else if (str.charAt(0) > '9' || str.charAt(0) < '0') {
return 0;
}
for (int i = index; i <= str.length() - 1; i++) {
digit = str.charAt(i) - '0';
overvalue = isSub * sum - Integer.MAX_VALUE / 10 + (((isSub + 1) / 2 + digit > 8) ? 1 : 0);
if ((digit < 0 || digit > 9)) {
break;
} else if (overvalue > 0) {
return isSub == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
sum = sum * 10 + isSub * digit;
}
return sum;
}