题目链接
题目描述
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
示例 1:
输入: "42"
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
解题思路
由题目和上述示例可以看出,一个正确的数字只有符号位与数字位组成的int型数值,其中符号位为空。这是一个中等难度的题,只需要将每个字符转换成数字加上就行(res = res * 10 + (char - ‘0’))。个人认为难点在于对数值边界和非法输入的判断 。
数值边界的判定:根据符号位设置一个边界值 Bound(值的大小等于 int 边界值的十分之一),只要此时的 res 小于 Bound ,那么加上这个字符所得的新数必然不可能越界;而 res == Bound 时,判断新加的数和 int 边界值的最后一位就可以了。
非法输入:null 、字符串长度为0、只有符号位、 不相关字符…
废话不多说,直接上代码。
// 输入判断
if (str == null) {
return 0;
}
char[] chars = str.trim().toCharArray();
if (chars.length == 0){
return 0;
}
int idx = 0;
int res = 0;
int sign = 1; // 正负标志
if (chars[0] == '+') {
idx++;
} else if (chars[0] == '-') {
sign = -1;
idx++;
}
int bound = sign == 1 ? Integer.MAX_VALUE / 10 : Integer.MIN_VALUE / 10;//根据符号位设置边界值
char currentChar;
int x;
for (int i = idx; i < chars.length; i++) {
currentChar = chars[i];
if (currentChar < '0' || currentChar > '9') {
//符号位后只能出现数字
break;
}
x = sign * (currentChar - '0');
if (sign == 1 && (res > bound || res == bound && x > Integer.MAX_VALUE % 10)) {
return Integer.MAX_VALUE;
} else if (sign == -1 && (res < bound || res == bound && x < Integer.MIN_VALUE % 10)) {
return Integer.MIN_VALUE;
} else {
res = res * 10 + x;
}
}
return res;
可以看到开头先是用了 trim()函数,直接找到第一个非空字符。此时要记得先去除首尾多余空格,再判断长度是否为0,否则会有 “ 若干空格 ” 进入程序中导致,chars【0】直接空指针异常
错题思路
- 使用StringBuilder将 ‘+’ | ‘-’ 和 数字拼接起来。
- 然后通过Integer.parseInt() 函数直接将拼接好的字符串
if (str == null || str.length() == 0) {
return 0;
}
char[] chars = str.trim().toCharArray();
StringBuilder sb = new StringBuilder();
int res = 0;
int count = 0; // 数字个数,判断是否越界
boolean sign = false; // FALSE 为 - ,TRUE 为 +
boolean appear = false; // 判断数字是否出现过
if (chars[0] == '-'){
sb.append(chars[0]);
}else if (chars[0] == '+') {
sign = true;
sb.append(chars[0]);
} else if (chars[0] > '0' && chars[0] <= '9') {
count++;
appear = true;
sb.append(chars[0]);
} else {
// 去除首尾空格后,合法数字的第一位必是 符号位 | 数字位
return 0;
}
for (int i = 1; i < chars.length; i++) {
if (chars[i] >= '0' && chars[i] <= '9') {
appear = true;
count++;
sb.append(chars[i]);
} else {
break;
}
}
if (appear) {
String tmp = sb.toString();
Long num = 0L;
// int 类型的最大值和最小值的十进制位数分别是 10、11
if (sign && count > 10) {
return Integer.MAX_VALUE;
}else if (!sign && count >11){
return Integer.MIN_VALUE;
}
num = Long.parseLong(tmp);
if (num > Integer.MAX_VALUE){
return Integer.MAX_VALUE;
} else if (num < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
res = Integer.parseInt(tmp);
}
return res;
这个思路出错的原因就是没有注意上面说的两点,以为使用了Long就能够避免值溢出;以为排除了空格和英文就没有了其他的非法输入,“00000013456”。
总结
主要就是锻炼你思维,如果你思考的时候,能够提前将各种输入字符串可能出现的非法输入,和数据类型的问题发现并分类处理,这题就不难。但是如果不能对把握对数字边界的判断,和字符串输入的种种可能就会走很多的弯路。
初写博客,如果有更好的解法和建议欢迎留言告诉我。