题目
请你来实现一个 myAtoi(string s)
函数,使其能将字符串转换成一个 32
位有符号整数(类似 C/C++
中的 atoi
函数)。
函数 myAtoi(string s)
的算法如下:
读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,"123
" -> 123
, "0032
" -> 32
)。如果没有读入数字,则整数为 0
。必要时更改符号(从步骤 2
开始)。
如果整数数超过 32
位有符号整数范围 [−231, 231 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231
的整数应该被固定为 −231
,大于 231 − 1
的整数应该被固定为 231 − 1
。
返回整数作为最终结果。
注意:
- 本题中的空白字符只包括空格字符 ' ' 。
- 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
示例 1:
输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"42"(读入 "42")
^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:
输入:s = " -42"
输出:-42
解释:
第 1 步:" -42"(读入前导空格,但忽视掉)
^
第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:" -42"(读入 "42")
^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:
输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。
示例 4:
输入:s = "words and 987"
输出:0
解释:
第 1 步:"words and 987"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"words and 987"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"words and 987"(由于当前字符 'w' 不是一个数字,所以读入停止)
^
解析得到整数 0 ,因为没有读入任何数字。
由于 0 在范围 [-231, 231 - 1] 内,最终结果为 0 。
示例 5:
输入:s = "-91283472332"
输出:-2147483648
解释:
第 1 步:"-91283472332"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"-91283472332"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:"-91283472332"(读入 "91283472332")
^
解析得到整数 -91283472332 。
由于 -91283472332 小于范围 [-231, 231 - 1] 的下界,最终结果被截断为 -231 = -2147483648 。
提示:
0 <= s.length <= 200 s 由英文字母(大写和小写)、数字(0-9)、' '、'+'、'-' 和 '.' 组成
思路与解答
这道题目看起来很长,但是实际上逻辑很清晰,就是将字符串解析成为数字,里面有几个特殊的规则:
- 1.前面的空格去掉,不读取
- 2.接下来的字符必须是数字,“
+
”号或者“-
”号- 2.1 如果是“
+
”号或者“-
”号,将符号记录下来 - 2.2 没有符号默认是“
+
”号,正数。
- 2.1 如果是“
- 3.接下来的字符必须是数字,遇到其他字符会直接结束
- 4.需要考虑溢出的问题
在将字符串转换成数字的时候,用下面这句核心代码:
sum = sum * 10 + (str.charAt(i) - '0');
但是在这个过程中,我们依然需要考虑数字溢出的问题,这个问题其实和我们上一道题【反转整数】一样:
针对这种情况,我们可以在加和之前判断,针对大于0的情况,如果大于最大值整除10,或者等于最大值整除10,但是个位数超过了,都直接返回0。
假设最大值是127,那么sum如果大于12,肯定会超过,如果sum ==12,但是个位数大于7,乘以10相加,也肯定会超。
if (sum > Integer.MAX_VALUE/10 || (sum == Integer.MAX_VALUE / 10 && (str.charAt(i) - '0') > 7)) return 0;
对于小于0
的情况,假设最小值是-128
,那么sum
是数字部分 128
, 如果当前sum
大于 12
,那么就一定超出,或者sum == 12
,但是个位数大于8
,乘以10
,相加也会大于128
,不符合要求,所以直接返回0
。
if (sum < Integer.MIN_VALUE/10 || (sum == Integer.MIN_VALUE / 10 && x (str.charAt(i) - '0') > 8)) return 0;
java代码实现如下:
class Solution {
public static int myAtoi(String str) {
if (str == null) {
return 0;
}
int i = 0;
while (i < str.length() && str.charAt(i) == ' ') {
i++;
}
if (i >= str.length()
|| (str.charAt(i) != '-'
&& str.charAt(i) != '+' && !((str.charAt(i) >= '0') && (str.charAt(i) <= '9')))) {
return 0;
}
int sign = 1;
if (i < str.length() && (str.charAt(i) == '-' || i < str.length() && str.charAt(i) == '+')) {
sign = str.charAt(i) == '-' ? -1 : 1;
i++;
}
int sum = 0;
for (; i < str.length(); i++) {
if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
if (sign == 1) {
if (sum > Integer.MAX_VALUE / 10 || sum == Integer.MAX_VALUE / 10 && (str.charAt(i) - '0') > 7) {
return Integer.MAX_VALUE;
}
} else {
if (sum > (Integer.MAX_VALUE) / 10 || sum == (Integer.MAX_VALUE) / 10 && (str.charAt(i) - '0') > 8) {
return Integer.MIN_VALUE;
}
}
sum = sum * 10 + (str.charAt(i) - '0');
} else {
return sum * sign;
}
}
return sum * sign;
}
}
C++ 代码实现如下:
#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
int myAtoi(string str) {
if (str.size() == 0) {
return 0;
}
int i = 0;
while (i < str.length() && str[i] == ' ') {
i++;
}
if (i >= str.length()
|| (str[i]!= '-'
&& str[i] != '+' && !((str[i] >= '0') && (str[i] <= '9')))) {
return 0;
}
int sign = 1;
if (i < str.length() && (str[i] == '-' || i < str.length() && str[i] == '+')) {
sign = str[i] == '-' ? -1 : 1;
i++;
}
// 需要无符号数,否则 -2147483648会溢出
unsigned int sum = 0;
for (; i < str.length(); i++) {
if (str[i] >= '0' && str[i] <= '9') {
if (sign == 1) {
if (sum > INT_MAX / 10 || sum == INT_MAX / 10 && (str[i]- '0') > 7) {
return INT_MAX;
}
} else {
if (sum > (INT_MAX) / 10 || sum == (INT_MAX) / 10 && (str[i] - '0') > 8) {
return INT_MIN;
}
}
sum = sum * 10 + (str[i] - '0');
} else {
return sum * sign;
}
}
return sum * sign;
}
};
int main(){
Solution solution;
cout<< solution.myAtoi(" -2147483648")<<endl;
return 0;
}
时间复杂度为 O(n),空间复杂度为O(1)。